This patch comes as a response to the discussions that took place after
I sent this patch upstream. It compiles out groups.c and also tries to
regroup the code in order to have all the functions in kernel/capability.c
that are to be conditionally compiled under a singe ifdef.
Note that struct init_groups and groups_alloc need to be defined somewhere
else (in another source file). If we make them static inline stubs in header,
other files which define these structs as extern and don't include linux/cred.h
will not be able to see their declaration and will fail with an undefined
reference compile error.
Also, in security/keys.c, key_task_permission is safe because groups_search
does not get to be called. may_setgroups function is only called in uid16.c,
which does not get compiled if CONFIG_NON_ROOT is not set. For the rest of
the functions defined in groups.c, all the places where they are called
select NON_ROOT (hope I did not miss anything).
I think we can do one more thing here - compiling out capability.c entirely.
Waiting for feedback if we should also try to do this in this patch.
The body of the is the following:
There are a lot of embedded systems that run most or all of their functionality
in init, running as root:root. For these systems, supporting multiple users is
not necessary.
This patch adds a new symbol, CONFIG_NON_ROOT, that makes support for non-root
users, non-root groups, and capabilities optional.
When this symbol is not defined, UID and GID are zero in any possible case
and processes always have all capabilities.
The following syscalls are compiled out: setuid, setregid, setgid,
setreuid, setresuid, getresuid, setresgid, getresgid, setgroups, getgroups,
setfsuid, setfsgid, capget, capset.
Also, groups.c is compiled out completely.
This change saves about 26 KB on a defconfig build.
Bloat-o-meter output:
add/remove: 7/86 grow/shrink: 27/428 up/down: 1733/-28111 (-26378)
arch/s390/Kconfig | 1 +
drivers/staging/lustre/lustre/Kconfig | 1 +
fs/nfsd/Kconfig | 1 +
include/linux/capability.h | 12 +++++
include/linux/cred.h | 21 ++++++--
include/linux/uidgid.h | 12 +++++
init/Kconfig | 19 +++++++-
kernel/Makefile | 4 +-
kernel/capability.c | 86 +++++++++++++++++----------------
kernel/cred.c | 8 +++
kernel/sys.c | 2 +
kernel/sys_ni.c | 14 ++++++
12 files changed, 134 insertions(+), 47 deletions(-)
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 68b68d7..ee7e45d 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -324,6 +324,7 @@ config COMPAT
select COMPAT_BINFMT_ELF if BINFMT_ELF
select ARCH_WANT_OLD_COMPAT_IPC
select COMPAT_OLD_SIGACTION
+ select NON_ROOT
help
Select this option if you want to enable your system kernel to
handle system-calls from ELF binaries for 31 bit ESA. This option
diff --git a/drivers/staging/lustre/lustre/Kconfig b/drivers/staging/lustre/lustre/Kconfig
index 6725467..655f413 100644
--- a/drivers/staging/lustre/lustre/Kconfig
+++ b/drivers/staging/lustre/lustre/Kconfig
@@ -10,6 +10,7 @@ config LUSTRE_FS
select CRYPTO_SHA1
select CRYPTO_SHA256
select CRYPTO_SHA512
+ select NON_ROOT
help
This option enables Lustre file system client support. Choose Y
here if you want to access a Lustre file system cluster. To compile
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index 7339515..c8a3b60 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -6,6 +6,7 @@ config NFSD
select SUNRPC
select EXPORTFS
select NFS_ACL_SUPPORT if NFSD_V2_ACL
+ select NON_ROOT
help
Choose Y here if you want to allow other computers to access
files residing on this system using Sun's Network File System
diff --git a/include/linux/capability.h b/include/linux/capability.h
index aa93e5e..d8791d2 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -211,8 +211,20 @@ extern bool has_ns_capability(struct task_struct *t,
extern bool has_capability_noaudit(struct task_struct *t, int cap);
extern bool has_ns_capability_noaudit(struct task_struct *t,
struct user_namespace *ns, int cap);
+#ifdef CONFIG_NON_ROOT
extern bool capable(int cap);
extern bool ns_capable(struct user_namespace *ns, int cap);
+#else
+static inline bool capable(int cap)
+{
+ return true;
+}
+
+static inline bool ns_capable(struct user_namespace *ns, int cap)
+{
+ return true;
+}
+#endif /* CONFIG_NON_ROOT */
extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap);
extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap);
diff --git a/include/linux/cred.h b/include/linux/cred.h
index 2fb2ca2..20b1234 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -64,7 +64,25 @@ do { \
extern struct group_info *groups_alloc(int);
extern struct group_info init_groups;
+#ifdef CONFIG_NON_ROOT
extern void groups_free(struct group_info *);
+
+extern int in_group_p(kgid_t);
+extern int in_egroup_p(kgid_t);
+#else
+static inline void groups_free(struct group_info *group_info)
+{
+}
+
+static inline int in_group_p(kgid_t grp)
+{
+ return 0;
+}
+static inline int in_egroup_p(kgid_t grp)
+{
+ return 0;
+}
+#endif
extern int set_current_groups(struct group_info *);
extern void set_groups(struct cred *, struct group_info *);
extern int groups_search(const struct group_info *, kgid_t);
@@ -74,9 +92,6 @@ extern bool may_setgroups(void);
#define GROUP_AT(gi, i) \
((gi)->blocks[(i) / NGROUPS_PER_BLOCK][(i) % NGROUPS_PER_BLOCK])
-extern int in_group_p(kgid_t);
-extern int in_egroup_p(kgid_t);
-
/*
* The security context of a task
*
diff --git a/kernel/Makefile b/kernel/Makefile
index a59481a..d5ca6b8 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -9,7 +9,9 @@ obj-y = fork.o exec_domain.o panic.o \
extable.o params.o \
kthread.o sys_ni.o nsproxy.o \
notifier.o ksysfs.o cred.o reboot.o \
- async.o range.o groups.o smpboot.o
+ async.o range.o smpboot.o
+
+obj-$(CONFIG_NON_ROOT) += groups.o
ifdef CONFIG_FUNCTION_TRACER
# Do not trace debug files and internal ftrace files
diff --git a/kernel/capability.c b/kernel/capability.c
index 989f5bf..17edd5b 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -35,6 +35,7 @@ static int __init file_caps_disable(char *str)
}
__setup("no_file_caps", file_caps_disable);
+#ifdef CONFIG_NON_ROOT
/*
* More recent versions of libcap are available from:
*
@@ -281,6 +282,49 @@ error:
}
/**
+ * ns_capable - Determine if the current task has a superior capability in effect
+ * @ns: The usernamespace we want the capability in
+ * @cap: The capability to be tested for
+ *
+ * Return true if the current task has the given superior capability currently
+ * available for use, false if not.
+ *
+ * This sets PF_SUPERPRIV on the task if the capability is available on the
+ * assumption that it's about to be used.
+ */
+bool ns_capable(struct user_namespace *ns, int cap)
+{
+ if (unlikely(!cap_valid(cap))) {
+ pr_crit("capable() called with invalid cap=%u\n", cap);
+ BUG();
+ }
+
+ if (security_capable(current_cred(), ns, cap) == 0) {
+ current->flags |= PF_SUPERPRIV;
+ return true;
+ }
+ return false;
+}
+EXPORT_SYMBOL(ns_capable);
+
+/**
+ * capable - Determine if the current task has a superior capability in effect
+ * @cap: The capability to be tested for
+ *
+ * Return true if the current task has the given superior capability currently
+ * available for use, false if not.
+ *
+ * This sets PF_SUPERPRIV on the task if the capability is available on the
+ * assumption that it's about to be used.
+ */
+bool capable(int cap)
+{
+ return ns_capable(&init_user_ns, cap);
+}
+EXPORT_SYMBOL(capable);
+#endif
+
+/**
* has_ns_capability - Does a task have a capability in a specific user ns
* @t: The task in question
* @ns: target user namespace
@@ -361,32 +405,6 @@ bool has_capability_noaudit(struct task_struct *t, int cap)
}
/**
- * ns_capable - Determine if the current task has a superior capability in effect
- * @ns: The usernamespace we want the capability in
- * @cap: The capability to be tested for
- *
- * Return true if the current task has the given superior capability currently
- * available for use, false if not.
- *
- * This sets PF_SUPERPRIV on the task if the capability is available on the
- * assumption that it's about to be used.
- */
-bool ns_capable(struct user_namespace *ns, int cap)
-{
- if (unlikely(!cap_valid(cap))) {
- pr_crit("capable() called with invalid cap=%u\n", cap);
- BUG();
- }
-
- if (security_capable(current_cred(), ns, cap) == 0) {
- current->flags |= PF_SUPERPRIV;
- return true;
- }
- return false;
-}
-EXPORT_SYMBOL(ns_capable);
-
-/**
* file_ns_capable - Determine if the file's opener had a capability in effect
* @file: The file we want to check
* @ns: The usernamespace we want the capability in
@@ -412,22 +430,6 @@ bool file_ns_capable(const struct file *file, struct user_namespace *ns,
EXPORT_SYMBOL(file_ns_capable);
/**
- * capable - Determine if the current task has a superior capability in effect
- * @cap: The capability to be tested for
- *
- * Return true if the current task has the given superior capability currently
- * available for use, false if not.
- *
- * This sets PF_SUPERPRIV on the task if the capability is available on the
- * assumption that it's about to be used.
- */
-bool capable(int cap)
-{
- return ns_capable(&init_user_ns, cap);
-}
-EXPORT_SYMBOL(capable);
-
-/**
* capable_wrt_inode_uidgid - Check nsown_capable and uid and gid mapped
* @inode: The inode in question
* @cap: The capability in question
diff --git a/kernel/cred.c b/kernel/cred.c
index e0573a4..e30c579 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -29,6 +29,14 @@
static struct kmem_cache *cred_jar;
+#if !defined(CONFIG_NON_ROOT)
+struct group_info init_groups;
+struct group_info *groups_alloc(int gidsetsize)
+{
+ return NULL;
+}
+#endif
+
/*
* The initial credentials for the initial task
*/