2004-09-12 05:46:29

by Lee Revell

[permalink] [raw]
Subject: [PATCH] Realtime LSM

The realtime-lsm Linux Security Module, written by Torben Hohn and Jack
O'Quin, selectively grants realtime capabilities to specific user groups
or applications. The typical use for this is low latency audio, and the
patch has been extensively field tested by Linux audio users. The
realtime LSM is a major improvement in security over the 2.4 capablities
patch and other workarounds like jackstart, which rely on CAP_SETPCAP.

Lee

Signed-Off-By: Lee Revell <[email protected]>

diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/Documentation/realtime-lsm.txt linux-2.6.8.1-rt/Documentation/realtime-lsm.txt
--- linux-2.6.8.1/Documentation/realtime-lsm.txt Wed Dec 31 18:00:00 1969
+++ linux-2.6.8.1-rt/Documentation/realtime-lsm.txt Fri Sep 10 20:38:42 2004
@@ -0,0 +1,47 @@
+
+ Realtime Linux Security Module
+
+
+This Linux Security Module (LSM) enables realtime capabilities. It
+was written by Torben Hohn and Jack O'Quin, under the provisions of
+the GPL (see the COPYING file). We make no warranty concerning the
+safety, security or even stability of your system when using it. But,
+we will fix problems if you report them.
+
+Once the LSM has been installed and the kernel for which it was built
+is running, the root user can load it and pass parameters as follows:
+
+ # modprobe realtime any=1
+
+ Any program can request realtime privileges. This allows any local
+ user to crash the system by hogging the CPU in a tight loop or
+ locking down too much memory. But, it is simple to administer. :-)
+
+ # modprobe realtime gid=29
+
+ All users belonging to group 29 and programs that are setgid to that
+ group have realtime privileges. Use any group number you like.
+
+ # modprobe realtime mlock=0
+
+ Grants realtime scheduling privileges without the ability to lock
+ memory using mlock() or mlockall() system calls. This option can be
+ used in conjunction with any of the other options.
+
+ # modprobe realtime allcaps=1
+
+ Enables all capabilities, including CAP_SETPCAP. This is equivalent
+ to the 2.4 kernel capabilities patch. It is needed for root
+ programs to assign realtime capabilities to other processes. This
+ option can be used in conjunction with any of the other options.
+
+ The JACK Audio Connection Kit (jackit.sourceforge.net) includes a
+ `jackstart' program which uses CAP_SETPCAP to run the JACK daemon
+ and its clients with realtime capabilities.
+
+ There are serious security exposures with CAP_SETPCAP. If an
+ attacker manages to subvert some system daemon running with root
+ privileges, it can use this capability to deny needed privileges to
+ other root processes.
+
+Jack O'Quin, [email protected]
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/security/Kconfig linux-2.6.8.1-rt/security/Kconfig
--- linux-2.6.8.1/security/Kconfig Sat Aug 14 05:55:47 2004
+++ linux-2.6.8.1-rt/security/Kconfig Fri Sep 10 11:03:40 2004
@@ -44,6 +44,20 @@

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

+config SECURITY_REALTIME
+ tristate "Realtime Capabilities"
+ depends on SECURITY && SECURITY_CAPABILITIES!=y
+ default n
+ help
+ Answer M to build realtime support as a Linux Security
+ Module. Answering Y to build realtime capabilities into the
+ kernel makes no sense.
+
+ This module selectively grants realtime privileges
+ controlled by load-time parameters.
+
+ If you are unsure how to answer this question, answer N.
+
source security/selinux/Kconfig

endmenu
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/security/Makefile linux-2.6.8.1-rt/security/Makefile
--- linux-2.6.8.1/security/Makefile Sat Aug 14 05:55:48 2004
+++ linux-2.6.8.1-rt/security/Makefile Fri Sep 10 19:00:31 2004
@@ -15,3 +15,4 @@
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_REALTIME) += commoncap.o realtime.o
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/security/realtime.c linux-2.6.8.1-rt/security/realtime.c
--- linux-2.6.8.1/security/realtime.c Wed Dec 31 18:00:00 1969
+++ linux-2.6.8.1-rt/security/realtime.c Fri Sep 10 11:09:09 2004
@@ -0,0 +1,226 @@
+/*
+ * Realtime Capabilities Linux Security Module
+ *
+ * Copyright (C) 2003 Torben Hohn
+ * Copyright (C) 2003, 2004 Jack O'Quin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/ptrace.h>
+
+#ifdef CONFIG_SECURITY
+
+#define RT_LSM "Realtime LSM " /* syslog module name prefix */
+#define RT_ERR "Realtime: " /* syslog error message prefix */
+
+#include <linux/vermagic.h>
+MODULE_INFO(vermagic,VERMAGIC_STRING);
+
+/* module parameters */
+static int any = 0; /* if TRUE, any process is realtime */
+MODULE_PARM(any, "i");
+MODULE_PARM_DESC(any, " grant realtime privileges to any process.");
+
+static int gid = -1; /* realtime group id, or NO_GROUP */
+MODULE_PARM(gid, "i");
+MODULE_PARM_DESC(gid, " the group ID with access to realtime privileges.");
+
+static int mlock = 1; /* enable mlock() privileges */
+MODULE_PARM(mlock, "i");
+MODULE_PARM_DESC(mlock, " enable memory locking privileges.");
+
+static int allcaps = 0; /* enable all capabilities */
+MODULE_PARM(allcaps, "i");
+MODULE_PARM_DESC(allcaps, " enable all capabilities, including CAP_SETPCAP.");
+
+static int debug = 0; /* verbose debug output */
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, " print verbose debug messages in syslog.");
+
+static kernel_cap_t cap_bset_save; /* place to save cap-bound */
+
+int realtime_bprm_set_security(struct linux_binprm *bprm)
+{
+ /* Copied from security/commoncap.c: cap_bprm_set_security()... */
+ /* Copied from fs/exec.c:prepare_binprm. */
+ /* We don't have VFS support for capabilities yet */
+ cap_clear(bprm->cap_inheritable);
+ cap_clear(bprm->cap_permitted);
+ cap_clear(bprm->cap_effective);
+
+ /* If a non-zero `any' parameter was specified, we grant
+ * realtime privileges to every process. If the `gid'
+ * parameter was specified and it matches the group id of the
+ * executable, of the current process or any supplementary
+ * groups, we grant realtime capabilites.
+ */
+
+ if (any || (gid != -1)) {
+
+ int rt_ok = 1;
+
+ /* check group permissions */
+ if ((gid != -1) &&
+ (gid != bprm->e_gid) &&
+ (gid != current->gid)) {
+ int i;
+ rt_ok = 0;
+#ifdef NGROUPS_SMALL /* using new groups struct? */
+ get_group_info(current->group_info);
+ for (i = 0; i < current->group_info->ngroups; ++i) {
+ if (gid == GROUP_AT(current->group_info, i)) {
+ rt_ok = 1;
+ break;
+ }
+ }
+ put_group_info(current->group_info);
+#else /* old task struct */
+ for (i = 0; i < NGROUPS; ++i) {
+ if (gid == current->groups[i]) {
+ rt_ok = 1;
+ break;
+ }
+ }
+#endif /* NGROUPS_SMALL */
+ }
+
+ if (rt_ok) {
+ cap_raise(bprm->cap_effective, CAP_SYS_NICE);
+ cap_raise(bprm->cap_permitted, CAP_SYS_NICE);
+ if (mlock) {
+ cap_raise(bprm->cap_effective, CAP_IPC_LOCK);
+ cap_raise(bprm->cap_permitted, CAP_IPC_LOCK);
+ cap_raise(bprm->cap_effective,
+ CAP_SYS_RESOURCE);
+ cap_raise(bprm->cap_permitted,
+ CAP_SYS_RESOURCE);
+ }
+ }
+ }
+
+ /* To support inheritance of root-permissions and suid-root
+ * executables under compatibility mode, we raise all three
+ * capability sets for the file.
+ *
+ * If only the real uid is 0, we only raise the inheritable
+ * and permitted sets of the executable file.
+ */
+
+ if (bprm->e_uid == 0 || current->uid == 0) {
+ cap_set_full (bprm->cap_inheritable);
+ cap_set_full (bprm->cap_permitted);
+ }
+ if (bprm->e_uid == 0)
+ cap_set_full (bprm->cap_effective);
+
+ return 0;
+}
+
+static struct security_operations capability_ops = {
+ .ptrace = cap_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+
+#ifdef LSM_UNSAFE_SHARE /* version >= 2.6.6 */
+ .bprm_apply_creds = cap_bprm_apply_creds,
+#else
+ .bprm_compute_creds = cap_bprm_compute_creds,
+#endif
+ .bprm_set_security = realtime_bprm_set_security,
+ .bprm_secureexec = cap_bprm_secureexec,
+
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+
+ .syslog = cap_syslog,
+
+ .vm_enough_memory = cap_vm_enough_memory,
+};
+
+#define MY_NAME THIS_MODULE->name
+
+/* flag to keep track of how we were registered */
+static int secondary;
+
+
+static int __init capability_init(void)
+{
+ /* register ourselves with the security framework */
+ if (register_security(&capability_ops)) {
+
+ /* try registering with primary module */
+ if (mod_reg_security(MY_NAME, &capability_ops)) {
+ printk(KERN_INFO RT_ERR "Failure registering "
+ "capabilities with primary security module.\n");
+ printk(KERN_INFO RT_ERR "Is kernel configured "
+ "with CONFIG_SECURITY_CAPABILITIES=m?\n");
+ return -EINVAL;
+ }
+ secondary = 1;
+ }
+
+ cap_bset_save = cap_bset; /* save cap-bound */
+ if (allcaps) {
+ cap_bset = to_cap_t(~0);
+ printk(KERN_INFO RT_LSM "enabling all capabilities\n");
+ }
+
+ if (any)
+ printk(KERN_INFO RT_LSM
+ "initialized (all groups, mlock=%d)\n", mlock);
+ else if (gid == -1)
+ printk(KERN_INFO RT_LSM
+ "initialized (no groups, mlock=%d)\n", mlock);
+ else
+ printk(KERN_INFO RT_LSM
+ "initialized (group %d, mlock=%d)\n", gid, mlock);
+
+ return 0;
+}
+
+static void __exit capability_exit(void)
+{
+ cap_bset = cap_bset_save; /* restore cap-bound */
+
+ /* remove ourselves from the security framework */
+ if (secondary) {
+ if (mod_unreg_security(MY_NAME, &capability_ops))
+ printk(KERN_INFO RT_ERR "Failure unregistering "
+ "capabilities with primary module.\n");
+
+ } else if (unregister_security(&capability_ops)) {
+ printk(KERN_INFO RT_ERR
+ "Failure unregistering capabilities with the kernel\n");
+ }
+ printk(KERN_INFO "Realtime Capability LSM exiting\n");
+}
+
+security_initcall(capability_init);
+module_exit(capability_exit);
+
+MODULE_DESCRIPTION("Realtime Capabilities Security Module");
+MODULE_LICENSE("GPL");
+
+#endif /* CONFIG_SECURITY */



2004-09-12 13:58:14

by James Morris

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Sun, 12 Sep 2004, Lee Revell wrote:

> +config SECURITY_REALTIME
> + tristate "Realtime Capabilities"
> + depends on SECURITY && SECURITY_CAPABILITIES!=y
> + default n
> + help
> + Answer M to build realtime support as a Linux Security
> + Module. Answering Y to build realtime capabilities into the
> + kernel makes no sense.

Why not just make it a bool then?

I wonder if it might be better to specify configuration via
/proc/<pid>/attr rather than module parameters.



- James
--
James Morris
<[email protected]>


2004-09-12 14:06:56

by James Morris

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Sun, 12 Sep 2004, James Morris wrote:

> Why not just make it a bool then?

Ignore that, I read the comment incorrectly.


- James
--
James Morris
<[email protected]>


2004-09-12 15:50:26

by Luca

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM


Lee Revell <[email protected]> ha scritto:
> The realtime-lsm Linux Security Module, written by Torben Hohn and Jack
> O'Quin, selectively grants realtime capabilities to specific user groups
> or applications.

Hi,
just a couple of comments:

> diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/security/realtime.c linux-2.6.8.1-rt/security/realtime.c
> --- linux-2.6.8.1/security/realtime.c Wed Dec 31 18:00:00 1969
> +++ linux-2.6.8.1-rt/security/realtime.c Fri Sep 10 11:09:09 2004
[...]
> +#ifdef NGROUPS_SMALL /* using new groups struct? */
> + get_group_info(current->group_info);
> + for (i = 0; i < current->group_info->ngroups; ++i) {
> + if (gid == GROUP_AT(current->group_info, i)) {
> + rt_ok = 1;
> + break;
> + }
> + }
> + put_group_info(current->group_info);
> +#else /* old task struct */
> + for (i = 0; i < NGROUPS; ++i) {
> + if (gid == current->groups[i]) {
> + rt_ok = 1;
> + break;
> + }
> + }
> +#endif /* NGROUPS_SMALL */

Since you are targeting linux 2.6.9 this ifdef can go away.

> +#ifdef LSM_UNSAFE_SHARE /* version >= 2.6.6 */
> + .bprm_apply_creds = cap_bprm_apply_creds,
> +#else
> + .bprm_compute_creds = cap_bprm_compute_creds,
> +#endif

Same here.

> +#define MY_NAME THIS_MODULE->name

This is ugly :P

Luca
--
Home: http://kronoz.cjb.net
Se alla sera, dopo una strepitosa vittoria, guardandoti allo
specchio dovessi notare un secondo paio di palle, che il tuo
cuore non si riempia d'orgoglio, perche` vuol dire che ti
stanno inculando -- Saggio Cinese

2004-09-12 19:03:48

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Sun, 2004-09-12 at 09:58, James Morris wrote:
> On Sun, 12 Sep 2004, Lee Revell wrote:
>
> > +config SECURITY_REALTIME
> > + tristate "Realtime Capabilities"
> > + depends on SECURITY && SECURITY_CAPABILITIES!=y
> > + default n
> > + help
> > + Answer M to build realtime support as a Linux Security
> > + Module. Answering Y to build realtime capabilities into the
> > + kernel makes no sense.
>
> Why not just make it a bool then?
>

Good idea.

> I wonder if it might be better to specify configuration via
> /proc/<pid>/attr rather than module parameters.
>

This would not work for several reasons. How would you decide who is
allowed to run RT processes? Root would have to set the above value,
which defeats the purpose of the realtime-lsm module which is to
selectively allow non-root users to run RT tasks.

Here is a good summary of the security issues that have been raised:

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=269661

Realtime-lsm solves all of these problems.

Lee

2004-09-12 19:17:02

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

James Morris <[email protected]> writes:

> I wonder if it might be better to specify configuration via
> /proc/<pid>/attr rather than module parameters.

We discussed configuration via /proc, and it seems worthwhile.

Maybe I don't understand the details of what you propose. I don't
find the /proc/<pid> approach attractive because it seems difficult to
administer. But, setting something global like /proc/realtime/group
or /proc/realtime/any would make a good enhancement to the current
interface.

I have not implemented that yet because (1) the current approach has
proven adequate for the Linux audio user community, and (2) I haven't
wanted to spend time mastering the internal kernel interfaces for
accessing /proc from an LSM. I know it's not difficult, but I had
other things I'd rather do. :-)

Thanks for the suggestion,
--
joq

2004-09-13 23:23:41

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Sun, 2004-09-12 at 11:50, Kronos wrote:
> Lee Revell <[email protected]> ha scritto:
> > The realtime-lsm Linux Security Module, written by Torben Hohn and Jack
> > O'Quin, selectively grants realtime capabilities to specific user groups
> > or applications.
>
> Hi,
> just a couple of comments:
>

OK, here's a cleaned up patch with the ifdefs removed and MY_NAME
define'd as __stringify(KBUILD_MODNAME).

Lee

---

Signed-Off-By: Lee Revell <[email protected]>

diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/Documentation/realtime-lsm.txt linux-2.6.8.1-rt/Documentation/realtime-lsm.txt
--- linux-2.6.8.1/Documentation/realtime-lsm.txt Wed Dec 31 18:00:00 1969
+++ linux-2.6.8.1-rt/Documentation/realtime-lsm.txt Fri Sep 10 20:38:42 2004
@@ -0,0 +1,47 @@
+
+ Realtime Linux Security Module
+
+
+This Linux Security Module (LSM) enables realtime capabilities. It
+was written by Torben Hohn and Jack O'Quin, under the provisions of
+the GPL (see the COPYING file). We make no warranty concerning the
+safety, security or even stability of your system when using it. But,
+we will fix problems if you report them.
+
+Once the LSM has been installed and the kernel for which it was built
+is running, the root user can load it and pass parameters as follows:
+
+ # modprobe realtime any=1
+
+ Any program can request realtime privileges. This allows any local
+ user to crash the system by hogging the CPU in a tight loop or
+ locking down too much memory. But, it is simple to administer. :-)
+
+ # modprobe realtime gid=29
+
+ All users belonging to group 29 and programs that are setgid to that
+ group have realtime privileges. Use any group number you like.
+
+ # modprobe realtime mlock=0
+
+ Grants realtime scheduling privileges without the ability to lock
+ memory using mlock() or mlockall() system calls. This option can be
+ used in conjunction with any of the other options.
+
+ # modprobe realtime allcaps=1
+
+ Enables all capabilities, including CAP_SETPCAP. This is equivalent
+ to the 2.4 kernel capabilities patch. It is needed for root
+ programs to assign realtime capabilities to other processes. This
+ option can be used in conjunction with any of the other options.
+
+ The JACK Audio Connection Kit (jackit.sourceforge.net) includes a
+ `jackstart' program which uses CAP_SETPCAP to run the JACK daemon
+ and its clients with realtime capabilities.
+
+ There are serious security exposures with CAP_SETPCAP. If an
+ attacker manages to subvert some system daemon running with root
+ privileges, it can use this capability to deny needed privileges to
+ other root processes.
+
+Jack O'Quin, [email protected]
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/security/Kconfig linux-2.6.8.1-rt/security/Kconfig
--- linux-2.6.8.1/security/Kconfig Sat Aug 14 05:55:47 2004
+++ linux-2.6.8.1-rt/security/Kconfig Fri Sep 10 11:03:40 2004
@@ -44,6 +44,20 @@

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

+config SECURITY_REALTIME
+ tristate "Realtime Capabilities"
+ depends on SECURITY && SECURITY_CAPABILITIES!=y
+ default n
+ help
+ Answer M to build realtime support as a Linux Security
+ Module. Answering Y to build realtime capabilities into the
+ kernel makes no sense.
+
+ This module selectively grants realtime privileges
+ controlled by load-time parameters.
+
+ If you are unsure how to answer this question, answer N.
+
source security/selinux/Kconfig

endmenu
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/security/Makefile linux-2.6.8.1-rt/security/Makefile
--- linux-2.6.8.1/security/Makefile Sat Aug 14 05:55:48 2004
+++ linux-2.6.8.1-rt/security/Makefile Fri Sep 10 19:00:31 2004
@@ -15,3 +15,4 @@
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_REALTIME) += commoncap.o realtime.o
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/security/realtime.c linux-2.6.8.1-rt/security/realtime.c
--- linux-2.6.8.1/security/realtime.c Wed Dec 31 18:00:00 1969
+++ linux-2.6.8.1-rt/security/realtime.c Fri Sep 10 11:09:09 2004
@@ -0,0 +1,206 @@
+/*
+ * Realtime Capabilities Linux Security Module
+ *
+ * Copyright (C) 2003 Torben Hohn
+ * Copyright (C) 2003, 2004 Jack O'Quin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/ptrace.h>
+
+#ifdef CONFIG_SECURITY
+
+#define RT_LSM "Realtime LSM " /* syslog module name prefix */
+#define RT_ERR "Realtime: " /* syslog error message prefix */
+
+#include <linux/vermagic.h>
+MODULE_INFO(vermagic,VERMAGIC_STRING);
+
+/* module parameters */
+static int any = 0; /* if TRUE, any process is realtime */
+MODULE_PARM(any, "i");
+MODULE_PARM_DESC(any, " grant realtime privileges to any process.");
+
+static int gid = -1; /* realtime group id, or NO_GROUP */
+MODULE_PARM(gid, "i");
+MODULE_PARM_DESC(gid, " the group ID with access to realtime privileges.");
+
+static int mlock = 1; /* enable mlock() privileges */
+MODULE_PARM(mlock, "i");
+MODULE_PARM_DESC(mlock, " enable memory locking privileges.");
+
+static int allcaps = 0; /* enable all capabilities */
+MODULE_PARM(allcaps, "i");
+MODULE_PARM_DESC(allcaps, " enable all capabilities, including CAP_SETPCAP.");
+
+static kernel_cap_t cap_bset_save; /* place to save cap-bound */
+
+int realtime_bprm_set_security(struct linux_binprm *bprm)
+{
+ /* Copied from security/commoncap.c: cap_bprm_set_security()... */
+ /* Copied from fs/exec.c:prepare_binprm. */
+ /* We don't have VFS support for capabilities yet */
+ cap_clear(bprm->cap_inheritable);
+ cap_clear(bprm->cap_permitted);
+ cap_clear(bprm->cap_effective);
+
+ /* If a non-zero `any' parameter was specified, we grant
+ * realtime privileges to every process. If the `gid'
+ * parameter was specified and it matches the group id of the
+ * executable, of the current process or any supplementary
+ * groups, we grant realtime capabilites.
+ */
+
+ if (any || (gid != -1)) {
+
+ int rt_ok = 1;
+
+ /* check group permissions */
+ if ((gid != -1) &&
+ (gid != bprm->e_gid) &&
+ (gid != current->gid)) {
+ int i;
+ rt_ok = 0;
+
+ get_group_info(current->group_info);
+ for (i = 0; i < current->group_info->ngroups; ++i) {
+ if (gid == GROUP_AT(current->group_info, i)) {
+ rt_ok = 1;
+ break;
+ }
+ }
+ put_group_info(current->group_info);
+ }
+
+ if (rt_ok) {
+ cap_raise(bprm->cap_effective, CAP_SYS_NICE);
+ cap_raise(bprm->cap_permitted, CAP_SYS_NICE);
+ if (mlock) {
+ cap_raise(bprm->cap_effective, CAP_IPC_LOCK);
+ cap_raise(bprm->cap_permitted, CAP_IPC_LOCK);
+ cap_raise(bprm->cap_effective,
+ CAP_SYS_RESOURCE);
+ cap_raise(bprm->cap_permitted,
+ CAP_SYS_RESOURCE);
+ }
+ }
+ }
+
+ /* To support inheritance of root-permissions and suid-root
+ * executables under compatibility mode, we raise all three
+ * capability sets for the file.
+ *
+ * If only the real uid is 0, we only raise the inheritable
+ * and permitted sets of the executable file.
+ */
+
+ if (bprm->e_uid == 0 || current->uid == 0) {
+ cap_set_full (bprm->cap_inheritable);
+ cap_set_full (bprm->cap_permitted);
+ }
+ if (bprm->e_uid == 0)
+ cap_set_full (bprm->cap_effective);
+
+ return 0;
+}
+
+static struct security_operations capability_ops = {
+ .ptrace = cap_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+ .bprm_apply_creds = cap_bprm_apply_creds,
+ .bprm_set_security = realtime_bprm_set_security,
+ .bprm_secureexec = cap_bprm_secureexec,
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+ .syslog = cap_syslog,
+ .vm_enough_memory = cap_vm_enough_memory,
+};
+
+#define MY_NAME __stringify(KBUILD_MODNAME)
+
+/* flag to keep track of how we were registered */
+static int secondary;
+
+
+static int __init capability_init(void)
+{
+ /* register ourselves with the security framework */
+ if (register_security(&capability_ops)) {
+
+ /* try registering with primary module */
+ if (mod_reg_security(MY_NAME, &capability_ops)) {
+ printk(KERN_INFO RT_ERR "Failure registering "
+ "capabilities with primary security module.\n");
+ printk(KERN_INFO RT_ERR "Is kernel configured "
+ "with CONFIG_SECURITY_CAPABILITIES=m?\n");
+ return -EINVAL;
+ }
+ secondary = 1;
+ }
+
+ cap_bset_save = cap_bset; /* save cap-bound */
+ if (allcaps) {
+ cap_bset = to_cap_t(~0);
+ printk(KERN_INFO RT_LSM "enabling all capabilities\n");
+ }
+
+ if (any)
+ printk(KERN_INFO RT_LSM
+ "initialized (all groups, mlock=%d)\n", mlock);
+ else if (gid == -1)
+ printk(KERN_INFO RT_LSM
+ "initialized (no groups, mlock=%d)\n", mlock);
+ else
+ printk(KERN_INFO RT_LSM
+ "initialized (group %d, mlock=%d)\n", gid, mlock);
+
+ return 0;
+}
+
+static void __exit capability_exit(void)
+{
+ cap_bset = cap_bset_save; /* restore cap-bound */
+
+ /* remove ourselves from the security framework */
+ if (secondary) {
+ if (mod_unreg_security(MY_NAME, &capability_ops))
+ printk(KERN_INFO RT_ERR "Failure unregistering "
+ "capabilities with primary module.\n");
+
+ } else if (unregister_security(&capability_ops)) {
+ printk(KERN_INFO RT_ERR
+ "Failure unregistering capabilities with the kernel\n");
+ }
+ printk(KERN_INFO "Realtime Capability LSM exiting\n");
+}
+
+security_initcall(capability_init);
+module_exit(capability_exit);
+
+MODULE_DESCRIPTION("Realtime Capabilities Security Module");
+MODULE_LICENSE("GPL");
+
+#endif /* CONFIG_SECURITY */


2004-09-13 23:35:33

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

* Lee Revell ([email protected]) wrote:
> +Once the LSM has been installed and the kernel for which it was built
> +is running, the root user can load it and pass parameters as follows:
> +
> + # modprobe realtime any=1
> +
> + Any program can request realtime privileges. This allows any local
> + user to crash the system by hogging the CPU in a tight loop or
> + locking down too much memory. But, it is simple to administer. :-)
> +
> + # modprobe realtime gid=29
> +
> + All users belonging to group 29 and programs that are setgid to that
> + group have realtime privileges. Use any group number you like.
> +
> + # modprobe realtime mlock=0
> +
> + Grants realtime scheduling privileges without the ability to lock
> + memory using mlock() or mlockall() system calls. This option can be
> + used in conjunction with any of the other options.
> +
> + # modprobe realtime allcaps=1
> +
> + Enables all capabilities, including CAP_SETPCAP. This is equivalent
> + to the 2.4 kernel capabilities patch. It is needed for root
> + programs to assign realtime capabilities to other processes. This
> + option can be used in conjunction with any of the other options.

The mlock() bit is unecessary now. Use rlimits on the audio users.
Which leaves realtime bits, plus others. I had a more generic module
(per-capability) that would be a superset of this. Perhaps that's a
better fit. I'm travelling this week, so forgive the spotty replies.

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-09-14 02:22:42

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Mon, 2004-09-13 at 19:34, Chris Wright wrote:
> * Lee Revell ([email protected]) wrote:
> > + # modprobe realtime mlock=0
> > +
> > + Grants realtime scheduling privileges without the ability to lock
> > + memory using mlock() or mlockall() system calls. This option can be
> > + used in conjunction with any of the other options.
> > +

> The mlock() bit is unecessary now. Use rlimits on the audio users.
> Which leaves realtime bits, plus others. I had a more generic module
> (per-capability) that would be a superset of this. Perhaps that's a
> better fit. I'm travelling this week, so forgive the spotty replies.

I think this would be fine. All we need is a way to allow users to run
SCHED_FIFO processes and use mlockall() without being root and without
having to patch the kernel. It's a pretty simple requirement.

Lee

2004-09-14 03:02:40

by William Lee Irwin III

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Mon, 2004-09-13 at 19:34, Chris Wright wrote:
>> The mlock() bit is unecessary now. Use rlimits on the audio users.
>> Which leaves realtime bits, plus others. I had a more generic module
>> (per-capability) that would be a superset of this. Perhaps that's a
>> better fit. I'm travelling this week, so forgive the spotty replies.

On Mon, Sep 13, 2004 at 10:18:06PM -0400, Lee Revell wrote:
> I think this would be fine. All we need is a way to allow users to run
> SCHED_FIFO processes and use mlockall() without being root and without
> having to patch the kernel. It's a pretty simple requirement.

Please construct a entitlement/permission checking scheme for this that
is not so lax as removing permissions checks altogether conditionally
on some sysctl.


-- wli

2004-09-14 03:50:56

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Mon, 2004-09-13 at 23:01, William Lee Irwin III wrote:
> On Mon, 2004-09-13 at 19:34, Chris Wright wrote:
> >> The mlock() bit is unecessary now. Use rlimits on the audio users.
> >> Which leaves realtime bits, plus others. I had a more generic module
> >> (per-capability) that would be a superset of this. Perhaps that's a
> >> better fit. I'm travelling this week, so forgive the spotty replies.
>
> On Mon, Sep 13, 2004 at 10:18:06PM -0400, Lee Revell wrote:
> > I think this would be fine. All we need is a way to allow users to run
> > SCHED_FIFO processes and use mlockall() without being root and without
> > having to patch the kernel. It's a pretty simple requirement.
>
> Please construct a entitlement/permission checking scheme for this that
> is not so lax as removing permissions checks altogether conditionally
> on some sysctl.

This is how it works now. You would typically do 'modprobe realtime
gid=29' and add audio users to that group. How is this any less secure
than the traditional user/group/other permissions model?

Lee

2004-09-14 03:53:13

by William Lee Irwin III

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Mon, 2004-09-13 at 23:01, William Lee Irwin III wrote:
>> Please construct a entitlement/permission checking scheme for this that
>> is not so lax as removing permissions checks altogether conditionally
>> on some sysctl.

On Mon, Sep 13, 2004 at 11:46:14PM -0400, Lee Revell wrote:
> This is how it works now. You would typically do 'modprobe realtime
> gid=29' and add audio users to that group. How is this any less secure
> than the traditional user/group/other permissions model?

I have no issue with uid/gid checks, thanks for clarifying.


-- wli

2004-09-16 02:32:17

by Jody McIntyre

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Sun, Sep 12, 2004 at 02:16:50PM -0500, Jack O'Quin wrote:

> I have not implemented that yet because (1) the current approach has
> proven adequate for the Linux audio user community, and (2) I haven't
> wanted to spend time mastering the internal kernel interfaces for
> accessing /proc from an LSM. I know it's not difficult, but I had
> other things I'd rather do. :-)

Here's a patch based on the one posted in
<[email protected]> that adds a sysctl
(/proc/sys) interface. These sysctls don't seem to fit into any of the
existing groups, so I added CTL_SECURITY (/proc/sys/security).

Example:

# modprobe realtime
# echo 29 > /proc/sys/security/realtime/gid

Signed-Off-By: Lee Revell <[email protected]>
Signed-off-by: Jody McIntyre <[email protected]>


Index: linux/Documentation/realtime-lsm.txt
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/Documentation/realtime-lsm.txt 2004-09-15 15:47:39.000000000 -0400
@@ -0,0 +1,47 @@
+
+ Realtime Linux Security Module
+
+
+This Linux Security Module (LSM) enables realtime capabilities. It
+was written by Torben Hohn and Jack O'Quin, under the provisions of
+the GPL (see the COPYING file). We make no warranty concerning the
+safety, security or even stability of your system when using it. But,
+we will fix problems if you report them.
+
+Once the LSM has been installed and the kernel for which it was built
+is running, the root user can load it and pass parameters as follows:
+
+ # modprobe realtime any=1
+
+ Any program can request realtime privileges. This allows any local
+ user to crash the system by hogging the CPU in a tight loop or
+ locking down too much memory. But, it is simple to administer. :-)
+
+ # modprobe realtime gid=29
+
+ All users belonging to group 29 and programs that are setgid to that
+ group have realtime privileges. Use any group number you like.
+
+ # modprobe realtime mlock=0
+
+ Grants realtime scheduling privileges without the ability to lock
+ memory using mlock() or mlockall() system calls. This option can be
+ used in conjunction with any of the other options.
+
+ # modprobe realtime allcaps=1
+
+ Enables all capabilities, including CAP_SETPCAP. This is equivalent
+ to the 2.4 kernel capabilities patch. It is needed for root
+ programs to assign realtime capabilities to other processes. This
+ option can be used in conjunction with any of the other options.
+
+ The JACK Audio Connection Kit (jackit.sourceforge.net) includes a
+ `jackstart' program which uses CAP_SETPCAP to run the JACK daemon
+ and its clients with realtime capabilities.
+
+ There are serious security exposures with CAP_SETPCAP. If an
+ attacker manages to subvert some system daemon running with root
+ privileges, it can use this capability to deny needed privileges to
+ other root processes.
+
+Jack O'Quin, [email protected]
Index: linux/security/Makefile
===================================================================
--- linux.orig/security/Makefile 2004-09-15 15:47:11.000000000 -0400
+++ linux/security/Makefile 2004-09-15 15:47:39.000000000 -0400
@@ -15,3 +15,4 @@ obj-$(CONFIG_SECURITY) += security.o d
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_REALTIME) += commoncap.o realtime.o
Index: linux/security/realtime.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/security/realtime.c 2004-09-15 17:54:18.000000000 -0400
@@ -0,0 +1,283 @@
+/*
+ * Realtime Capabilities Linux Security Module
+ *
+ * Copyright (C) 2003 Torben Hohn
+ * Copyright (C) 2003, 2004 Jack O'Quin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/ptrace.h>
+#include <linux/sysctl.h>
+
+#ifdef CONFIG_SECURITY
+
+#define RT_LSM "Realtime LSM " /* syslog module name prefix */
+#define RT_ERR "Realtime: " /* syslog error message prefix */
+
+#include <linux/vermagic.h>
+MODULE_INFO(vermagic,VERMAGIC_STRING);
+
+/* this is needed for the proc_dointvec_minmax for allowed GID */
+static int maxuid = 65535;
+static int minuid = -1;
+
+/* module parameters */
+static int any = 0; /* if TRUE, any process is realtime */
+MODULE_PARM(any, "i");
+MODULE_PARM_DESC(any, " grant realtime privileges to any process.");
+
+static int gid = -1; /* realtime group id, or NO_GROUP */
+MODULE_PARM(gid, "i");
+MODULE_PARM_DESC(gid, " the group ID with access to realtime privileges.");
+
+static int mlock = 1; /* enable mlock() privileges */
+MODULE_PARM(mlock, "i");
+MODULE_PARM_DESC(mlock, " enable memory locking privileges.");
+
+static int allcaps = 0; /* enable all capabilities */
+MODULE_PARM(allcaps, "i");
+MODULE_PARM_DESC(allcaps, " enable all capabilities, including CAP_SETPCAP.");
+
+static kernel_cap_t cap_bset_save; /* place to save cap-bound */
+
+int realtime_bprm_set_security(struct linux_binprm *bprm)
+{
+ /* Copied from security/commoncap.c: cap_bprm_set_security()... */
+ /* Copied from fs/exec.c:prepare_binprm. */
+ /* We don't have VFS support for capabilities yet */
+ cap_clear(bprm->cap_inheritable);
+ cap_clear(bprm->cap_permitted);
+ cap_clear(bprm->cap_effective);
+
+ /* If a non-zero `any' parameter was specified, we grant
+ * realtime privileges to every process. If the `gid'
+ * parameter was specified and it matches the group id of the
+ * executable, of the current process or any supplementary
+ * groups, we grant realtime capabilites.
+ */
+
+ if (any || (gid != -1)) {
+
+ int rt_ok = 1;
+
+ /* check group permissions */
+ if ((gid != -1) &&
+ (gid != bprm->e_gid) &&
+ (gid != current->gid)) {
+ int i;
+ rt_ok = 0;
+
+ get_group_info(current->group_info);
+ for (i = 0; i < current->group_info->ngroups; ++i) {
+ if (gid == GROUP_AT(current->group_info, i)) {
+ rt_ok = 1;
+ break;
+ }
+ }
+ put_group_info(current->group_info);
+ }
+
+ if (rt_ok) {
+ cap_raise(bprm->cap_effective, CAP_SYS_NICE);
+ cap_raise(bprm->cap_permitted, CAP_SYS_NICE);
+ if (mlock) {
+ cap_raise(bprm->cap_effective, CAP_IPC_LOCK);
+ cap_raise(bprm->cap_permitted, CAP_IPC_LOCK);
+ cap_raise(bprm->cap_effective,
+ CAP_SYS_RESOURCE);
+ cap_raise(bprm->cap_permitted,
+ CAP_SYS_RESOURCE);
+ }
+ }
+ }
+
+ /* To support inheritance of root-permissions and suid-root
+ * executables under compatibility mode, we raise all three
+ * capability sets for the file.
+ *
+ * If only the real uid is 0, we only raise the inheritable
+ * and permitted sets of the executable file.
+ */
+
+ if (bprm->e_uid == 0 || current->uid == 0) {
+ cap_set_full (bprm->cap_inheritable);
+ cap_set_full (bprm->cap_permitted);
+ }
+ if (bprm->e_uid == 0)
+ cap_set_full (bprm->cap_effective);
+
+ return 0;
+}
+
+static struct security_operations capability_ops = {
+ .ptrace = cap_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+ .bprm_apply_creds = cap_bprm_apply_creds,
+ .bprm_set_security = realtime_bprm_set_security,
+ .bprm_secureexec = cap_bprm_secureexec,
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+ .syslog = cap_syslog,
+ .vm_enough_memory = cap_vm_enough_memory,
+};
+
+#define MY_NAME __stringify(KBUILD_MODNAME)
+
+static ctl_table realtime_table[] =
+{
+ { .ctl_name = 1,
+ .procname = "any",
+ .data = &any,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { .ctl_name = 2,
+ .procname = "gid",
+ .data = &gid,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = &minuid,
+ .extra2 = &maxuid
+ },
+ { .ctl_name = 3,
+ .procname = "mlock",
+ .data = &mlock,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { .ctl_name = 4,
+ .procname = "allcaps",
+ .data = &allcaps,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { }
+};
+
+static ctl_table realtime_root_table[] =
+{
+ { .ctl_name = SECURITY_REALTIME,
+ .procname = "realtime",
+ .mode = 0555,
+ .child = realtime_table },
+ { }
+};
+
+static ctl_table security_root_table[] =
+{
+ { .ctl_name = CTL_SECURITY,
+ .procname = "security",
+ .mode = 0555,
+ .child = realtime_root_table },
+ { }
+};
+
+static struct ctl_table_header *sysctl_header;
+
+static void __exit exit_sysctl(void)
+{
+ unregister_sysctl_table(sysctl_header);
+}
+
+/* flag to keep track of how we were registered */
+static int secondary;
+
+static void __exit exit_security(void)
+{
+ cap_bset = cap_bset_save; /* restore cap-bound */
+
+ /* remove ourselves from the security framework */
+ if (secondary) {
+ if (mod_unreg_security(MY_NAME, &capability_ops))
+ printk(KERN_INFO RT_ERR "Failure unregistering "
+ "capabilities with primary module.\n");
+
+ } else if (unregister_security(&capability_ops)) {
+ printk(KERN_INFO RT_ERR
+ "Failure unregistering capabilities with the kernel\n");
+ }
+ printk(KERN_INFO "Realtime Capability LSM exiting\n");
+}
+
+static int __init capability_init(void)
+{
+ /* register ourselves with the security framework */
+ if (register_security(&capability_ops)) {
+
+ /* try registering with primary module */
+ if (mod_reg_security(MY_NAME, &capability_ops)) {
+ printk(KERN_INFO RT_ERR "Failure registering "
+ "capabilities with primary security module.\n");
+ printk(KERN_INFO RT_ERR "Is kernel configured "
+ "with CONFIG_SECURITY_CAPABILITIES=m?\n");
+ return -EINVAL;
+ }
+ secondary = 1;
+ }
+
+ cap_bset_save = cap_bset; /* save cap-bound */
+
+ sysctl_header = register_sysctl_table(security_root_table, 0);
+ if (!sysctl_header) {
+ exit_security();
+ return -ENOMEM;
+ }
+
+ if (allcaps) {
+ cap_bset = to_cap_t(~0);
+ printk(KERN_INFO RT_LSM "enabling all capabilities\n");
+ }
+
+ if (any)
+ printk(KERN_INFO RT_LSM
+ "initialized (all groups, mlock=%d)\n", mlock);
+ else if (gid == -1)
+ printk(KERN_INFO RT_LSM
+ "initialized (no groups, mlock=%d)\n", mlock);
+ else
+ printk(KERN_INFO RT_LSM
+ "initialized (group %d, mlock=%d)\n", gid, mlock);
+
+ return 0;
+}
+
+static void __exit capability_exit(void)
+{
+ exit_sysctl();
+ exit_security();
+}
+
+security_initcall(capability_init);
+module_exit(capability_exit);
+
+MODULE_DESCRIPTION("Realtime Capabilities Security Module");
+MODULE_LICENSE("GPL");
+
+#endif /* CONFIG_SECURITY */
Index: linux/include/linux/sysctl.h
===================================================================
--- linux.orig/include/linux/sysctl.h 2004-09-15 11:59:54.000000000 -0400
+++ linux/include/linux/sysctl.h 2004-09-15 16:56:21.000000000 -0400
@@ -61,7 +61,14 @@ enum
CTL_DEV=7, /* Devices */
CTL_BUS=8, /* Busses */
CTL_ABI=9, /* Binary emulation */
- CTL_CPU=10 /* CPU stuff (speed scaling, etc) */
+ CTL_CPU=10, /* CPU stuff (speed scaling, etc) */
+ CTL_SECURITY=11 /* Security modules */
+};
+
+/* CTL_SECURITY names: */
+enum
+{
+ SECURITY_REALTIME=1 /* Realtime LSM */
};

/* CTL_BUS names: */
Index: linux/security/Kconfig
===================================================================
--- linux.orig/security/Kconfig 2004-09-15 15:47:11.000000000 -0400
+++ linux/security/Kconfig 2004-09-15 15:47:39.000000000 -0400
@@ -44,6 +44,20 @@ config SECURITY_ROOTPLUG

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

+config SECURITY_REALTIME
+ tristate "Realtime Capabilities"
+ depends on SECURITY && SECURITY_CAPABILITIES!=y
+ default n
+ help
+ Answer M to build realtime support as a Linux Security
+ Module. Answering Y to build realtime capabilities into the
+ kernel makes no sense.
+
+ This module selectively grants realtime privileges
+ controlled by load-time parameters.
+
+ If you are unsure how to answer this question, answer N.
+
source security/selinux/Kconfig

endmenu

2004-09-16 04:51:43

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

Jody McIntyre <[email protected]> writes:

> On Sun, Sep 12, 2004 at 02:16:50PM -0500, Jack O'Quin wrote:
>
> > I have not implemented that yet because (1) the current approach has
> > proven adequate for the Linux audio user community, and (2) I haven't
> > wanted to spend time mastering the internal kernel interfaces for
> > accessing /proc from an LSM. I know it's not difficult, but I had
> > other things I'd rather do. :-)
>
> Here's a patch based on the one posted in
> <[email protected]> that adds a sysctl
> (/proc/sys) interface. These sysctls don't seem to fit into any of the
> existing groups, so I added CTL_SECURITY (/proc/sys/security).
>
> Example:
>
> # modprobe realtime
> # echo 29 > /proc/sys/security/realtime/gid

Thanks! That's even cleaner than I had realized. I like it.

What are the serialization issues with variable updates via /proc? I
presume they can change at any time, even while the LSM is running on
some other processor. If so, I'll need to be careful to fetch each
variable only once and use that value for the entire capability
computation, right? That should be straightforward.

The only LSM option that doesn't fit this model is `allcaps', which
only functions at initialization time (by adding CAP_SETPCAP to the
capability bounds). My initial thought is that we probably don't want
that to change via /proc, so just leave it out of the sysctl list.

But, perhaps we should consider removing this option entirely. It is
the only one with a potentially serious security exposure. The others
at worst allow Denial of Service attacks.

`Allcaps' is there for compatibility with 2.4 kernels with the so-
called "capabilities patch". Many Linux audio users run that way so
they can use the JACK Audio Connection Kit without being root. With
`allcaps' the same methods work with either kernel. This is not
strictly necessary, because the Realtime LSM provides the required
capabilities without `allcaps'. But, it is convenient for people like
me who maintain programs on both kernel versions and frequently switch
back and forth for testing purposes.

Because 2.4 with the low-latency patches provides outstanding realtime
performance, many serious audio users have not yet moved to 2.6. With
the excellent results recently reported with 2.6 patched for low
latency, that may soon change (especially when some of these patches
have been integrated into the mainline kernel).

Since the long-term need for `allcaps' is unclear, maybe it should be
enabled by a separate `experimental' Kconfig option accompanied with
appropriate security warnings. Eventually, we might want to phase it
out entirely.
--
joq

2004-09-16 15:57:15

by Jody McIntyre

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Wed, Sep 15, 2004 at 11:48:29PM -0500, Jack O'Quin wrote:

> What are the serialization issues with variable updates via /proc? I
> presume they can change at any time, even while the LSM is running on
> some other processor. If so, I'll need to be careful to fetch each
> variable only once and use that value for the entire capability
> computation, right? That should be straightforward.

It doesn't matter. There's no added security risk if gid changes
halfway through the permission check, and the other variables are used
only once. It's probably cleaner to check the gid in a separate
function though.

However, I just noticed something interesting:

If "any" and "gid" is set, any is ignored and only the gid check is
effective. This is counter to the documentation, so I assume it is a
bug.

So I made gid checking a separate function and fixed the any+gid bug.
See patch.

> The only LSM option that doesn't fit this model is `allcaps', which
> only functions at initialization time (by adding CAP_SETPCAP to the
> capability bounds). My initial thought is that we probably don't want
> that to change via /proc, so just leave it out of the sysctl list.

You're right. Sorry I missed that. The patch below removes the
(useless) sysctl for allcaps.

I also added the sysctl interface to the documentation.

> But, perhaps we should consider removing this option entirely. It is
> the only one with a potentially serious security exposure. The others
> at worst allow Denial of Service attacks.
>
> [...]

I hate allcaps too. Maybe you should just use a shell script wrapper
like (untested):

----
if echo uname -r |grep '^2\.4\.' ; then
jackstart $@
else
jackd $@
fi
----

Anyway, here's the patch:


The realtime-lsm Linux Security Module, written by Torben Hohn and Jack
O'Quin, selectively grants realtime capabilities to specific user groups
or applications. The typical use for this is low latency audio, and the
patch has been extensively field tested by Linux audio users. The
realtime LSM is a major improvement in security over the 2.4 capablities
patch and other workarounds like jackstart, which rely on CAP_SETPCAP.

Signed-Off-By: Lee Revell <[email protected]>
Signed-off-by: Jody McIntyre <[email protected]>

Index: linux/Documentation/realtime-lsm.txt
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/Documentation/realtime-lsm.txt 2004-09-16 10:54:04.699104400 -0400
@@ -0,0 +1,50 @@
+
+ Realtime Linux Security Module
+
+
+This Linux Security Module (LSM) enables realtime capabilities. It
+was written by Torben Hohn and Jack O'Quin, under the provisions of
+the GPL (see the COPYING file). We make no warranty concerning the
+safety, security or even stability of your system when using it. But,
+we will fix problems if you report them.
+
+Once the LSM has been installed and the kernel for which it was built
+is running, the root user can load it and pass parameters as follows:
+
+ # modprobe realtime any=1
+
+ Any program can request realtime privileges. This allows any local
+ user to crash the system by hogging the CPU in a tight loop or
+ locking down too much memory. But, it is simple to administer. :-)
+
+ # modprobe realtime gid=29
+
+ All users belonging to group 29 and programs that are setgid to that
+ group have realtime privileges. Use any group number you like.
+
+ # modprobe realtime mlock=0
+
+ Grants realtime scheduling privileges without the ability to lock
+ memory using mlock() or mlockall() system calls. This option can be
+ used in conjunction with any of the other options.
+
+ # modprobe realtime allcaps=1
+
+ Enables all capabilities, including CAP_SETPCAP. This is equivalent
+ to the 2.4 kernel capabilities patch. It is needed for root
+ programs to assign realtime capabilities to other processes. This
+ option can be used in conjunction with any of the other options.
+
+ The JACK Audio Connection Kit (jackit.sourceforge.net) includes a
+ `jackstart' program which uses CAP_SETPCAP to run the JACK daemon
+ and its clients with realtime capabilities.
+
+ There are serious security exposures with CAP_SETPCAP. If an
+ attacker manages to subvert some system daemon running with root
+ privileges, it can use this capability to deny needed privileges to
+ other root processes.
+
+All parameters apart from allcaps can also be changed dynamically via
+the entries in /proc/sys/security/realtime.
+
+Jack O'Quin, [email protected]
Index: linux/security/Makefile
===================================================================
--- linux.orig/security/Makefile 2004-09-15 15:47:11.000000000 -0400
+++ linux/security/Makefile 2004-09-15 15:47:39.000000000 -0400
@@ -15,3 +15,4 @@ obj-$(CONFIG_SECURITY) += security.o d
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_REALTIME) += commoncap.o realtime.o
Index: linux/security/realtime.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/security/realtime.c 2004-09-16 11:45:30.799945760 -0400
@@ -0,0 +1,274 @@
+/*
+ * Realtime Capabilities Linux Security Module
+ *
+ * Copyright (C) 2003 Torben Hohn
+ * Copyright (C) 2003, 2004 Jack O'Quin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/ptrace.h>
+#include <linux/sysctl.h>
+
+#ifdef CONFIG_SECURITY
+
+#define RT_LSM "Realtime LSM " /* syslog module name prefix */
+#define RT_ERR "Realtime: " /* syslog error message prefix */
+
+#include <linux/vermagic.h>
+MODULE_INFO(vermagic,VERMAGIC_STRING);
+
+/* this is needed for the proc_dointvec_minmax for allowed GID */
+static int maxuid = 65535;
+static int minuid = -1;
+
+/* module parameters */
+static int any = 0; /* if TRUE, any process is realtime */
+MODULE_PARM(any, "i");
+MODULE_PARM_DESC(any, " grant realtime privileges to any process.");
+
+static int gid = -1; /* realtime group id, or NO_GROUP */
+MODULE_PARM(gid, "i");
+MODULE_PARM_DESC(gid, " the group ID with access to realtime privileges.");
+
+static int mlock = 1; /* enable mlock() privileges */
+MODULE_PARM(mlock, "i");
+MODULE_PARM_DESC(mlock, " enable memory locking privileges.");
+
+static int allcaps = 0; /* enable all capabilities */
+MODULE_PARM(allcaps, "i");
+MODULE_PARM_DESC(allcaps, " enable all capabilities, including CAP_SETPCAP.");
+
+static int gid_ok(int gid, int e_gid) {
+ int i;
+ int rt_ok = 0;
+
+ if (gid == -1)
+ return 0;
+
+ if ((gid == e_gid) || (gid == current->gid))
+ return 1;
+
+ get_group_info(current->group_info);
+ for (i = 0; i < current->group_info->ngroups; ++i) {
+ if (gid == GROUP_AT(current->group_info, i)) {
+ rt_ok = 1;
+ break;
+ }
+ }
+ put_group_info(current->group_info);
+
+ return rt_ok;
+}
+
+int realtime_bprm_set_security(struct linux_binprm *bprm)
+{
+ /* Copied from security/commoncap.c: cap_bprm_set_security()... */
+ /* Copied from fs/exec.c:prepare_binprm. */
+ /* We don't have VFS support for capabilities yet */
+ cap_clear(bprm->cap_inheritable);
+ cap_clear(bprm->cap_permitted);
+ cap_clear(bprm->cap_effective);
+
+ /* If a non-zero `any' parameter was specified, we grant
+ * realtime privileges to every process. If the `gid'
+ * parameter was specified and it matches the group id of the
+ * executable, of the current process or any supplementary
+ * groups, we grant realtime capabilites.
+ */
+
+ if (any || gid_ok(gid, bprm->e_gid)) {
+ cap_raise(bprm->cap_effective, CAP_SYS_NICE);
+ cap_raise(bprm->cap_permitted, CAP_SYS_NICE);
+ if (mlock) {
+ cap_raise(bprm->cap_effective, CAP_IPC_LOCK);
+ cap_raise(bprm->cap_permitted, CAP_IPC_LOCK);
+ cap_raise(bprm->cap_effective,
+ CAP_SYS_RESOURCE);
+ cap_raise(bprm->cap_permitted,
+ CAP_SYS_RESOURCE);
+ }
+ }
+
+ /* To support inheritance of root-permissions and suid-root
+ * executables under compatibility mode, we raise all three
+ * capability sets for the file.
+ *
+ * If only the real uid is 0, we only raise the inheritable
+ * and permitted sets of the executable file.
+ */
+
+ if (bprm->e_uid == 0 || current->uid == 0) {
+ cap_set_full(bprm->cap_inheritable);
+ cap_set_full(bprm->cap_permitted);
+ }
+ if (bprm->e_uid == 0)
+ cap_set_full(bprm->cap_effective);
+
+ return 0;
+}
+
+static struct security_operations capability_ops = {
+ .ptrace = cap_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+ .bprm_apply_creds = cap_bprm_apply_creds,
+ .bprm_set_security = realtime_bprm_set_security,
+ .bprm_secureexec = cap_bprm_secureexec,
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+ .syslog = cap_syslog,
+ .vm_enough_memory = cap_vm_enough_memory,
+};
+
+#define MY_NAME __stringify(KBUILD_MODNAME)
+
+static ctl_table realtime_table[] =
+{
+ { .ctl_name = 1,
+ .procname = "any",
+ .data = &any,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { .ctl_name = 2,
+ .procname = "gid",
+ .data = &gid,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = &minuid,
+ .extra2 = &maxuid
+ },
+ { .ctl_name = 3,
+ .procname = "mlock",
+ .data = &mlock,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { }
+};
+
+static ctl_table realtime_root_table[] =
+{
+ { .ctl_name = SECURITY_REALTIME,
+ .procname = "realtime",
+ .mode = 0555,
+ .child = realtime_table },
+ { }
+};
+
+static ctl_table security_root_table[] =
+{
+ { .ctl_name = CTL_SECURITY,
+ .procname = "security",
+ .mode = 0555,
+ .child = realtime_root_table },
+ { }
+};
+
+static struct ctl_table_header *sysctl_header;
+
+static void __exit exit_sysctl(void)
+{
+ unregister_sysctl_table(sysctl_header);
+}
+
+static int secondary; /* flag to keep track of how we were registered */
+static kernel_cap_t cap_bset_save; /* place to save cap-bound */
+
+static void __exit exit_security(void)
+{
+ cap_bset = cap_bset_save; /* restore cap-bound */
+
+ /* remove ourselves from the security framework */
+ if (secondary) {
+ if (mod_unreg_security(MY_NAME, &capability_ops))
+ printk(KERN_INFO RT_ERR "Failure unregistering "
+ "capabilities with primary module.\n");
+
+ } else if (unregister_security(&capability_ops)) {
+ printk(KERN_INFO RT_ERR
+ "Failure unregistering capabilities with the kernel\n");
+ }
+ printk(KERN_INFO "Realtime Capability LSM exiting\n");
+}
+
+static int __init capability_init(void)
+{
+ /* register ourselves with the security framework */
+ if (register_security(&capability_ops)) {
+
+ /* try registering with primary module */
+ if (mod_reg_security(MY_NAME, &capability_ops)) {
+ printk(KERN_INFO RT_ERR "Failure registering "
+ "capabilities with primary security module.\n");
+ printk(KERN_INFO RT_ERR "Is kernel configured "
+ "with CONFIG_SECURITY_CAPABILITIES=m?\n");
+ return -EINVAL;
+ }
+ secondary = 1;
+ }
+
+ cap_bset_save = cap_bset; /* save cap-bound */
+
+ sysctl_header = register_sysctl_table(security_root_table, 0);
+ if (!sysctl_header) {
+ exit_security();
+ return -ENOMEM;
+ }
+
+ if (allcaps) {
+ cap_bset = to_cap_t(~0);
+ printk(KERN_INFO RT_LSM "enabling all capabilities\n");
+ }
+
+ if (any)
+ printk(KERN_INFO RT_LSM
+ "initialized (all groups, mlock=%d)\n", mlock);
+ else if (gid == -1)
+ printk(KERN_INFO RT_LSM
+ "initialized (no groups, mlock=%d)\n", mlock);
+ else
+ printk(KERN_INFO RT_LSM
+ "initialized (group %d, mlock=%d)\n", gid, mlock);
+
+ return 0;
+}
+
+static void __exit capability_exit(void)
+{
+ exit_sysctl();
+ exit_security();
+}
+
+security_initcall(capability_init);
+module_exit(capability_exit);
+
+MODULE_DESCRIPTION("Realtime Capabilities Security Module");
+MODULE_LICENSE("GPL");
+
+#endif /* CONFIG_SECURITY */
Index: linux/include/linux/sysctl.h
===================================================================
--- linux.orig/include/linux/sysctl.h 2004-09-15 11:59:54.000000000 -0400
+++ linux/include/linux/sysctl.h 2004-09-15 16:56:21.000000000 -0400
@@ -61,7 +61,14 @@ enum
CTL_DEV=7, /* Devices */
CTL_BUS=8, /* Busses */
CTL_ABI=9, /* Binary emulation */
- CTL_CPU=10 /* CPU stuff (speed scaling, etc) */
+ CTL_CPU=10, /* CPU stuff (speed scaling, etc) */
+ CTL_SECURITY=11 /* Security modules */
+};
+
+/* CTL_SECURITY names: */
+enum
+{
+ SECURITY_REALTIME=1 /* Realtime LSM */
};

/* CTL_BUS names: */
Index: linux/security/Kconfig
===================================================================
--- linux.orig/security/Kconfig 2004-09-15 15:47:11.000000000 -0400
+++ linux/security/Kconfig 2004-09-16 11:49:03.920546504 -0400
@@ -44,6 +44,21 @@ config SECURITY_ROOTPLUG

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

+config SECURITY_REALTIME
+ tristate "Realtime Capabilities"
+ depends on SECURITY && SECURITY_CAPABILITIES!=y
+ default n
+ help
+ Answer M to build realtime support as a Linux Security
+ Module. Answering Y to build realtime capabilities into the
+ kernel makes no sense.
+
+ This module selectively grants realtime privileges
+ controlled by load-time parameters and
+ /proc/sys/security/realtime.
+
+ If you are unsure how to answer this question, answer N.
+
source security/selinux/Kconfig

endmenu

2004-09-16 18:32:06

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

Jody McIntyre <[email protected]> writes:

> On Wed, Sep 15, 2004 at 11:48:29PM -0500, Jack O'Quin wrote:
>
> > What are the serialization issues with variable updates via /proc? I
> > presume they can change at any time, even while the LSM is running on
> > some other processor. If so, I'll need to be careful to fetch each
> > variable only once and use that value for the entire capability
> > computation, right? That should be straightforward.
>
> It doesn't matter. There's no added security risk if gid changes
> halfway through the permission check, and the other variables are used
> only once. It's probably cleaner to check the gid in a separate
> function though.

Agreed.

One could probably get a false negative, but it's hard to imagine a
sensible usage example. I just like to be tidy any time concurrency
issues arise.

> However, I just noticed something interesting:
>
> If "any" and "gid" is set, any is ignored and only the gid check is
> effective. This is counter to the documentation, so I assume it is a
> bug.

Quite right, good eye. :-)

I must not have tested that combination. :-(

> I also added the sysctl interface to the documentation.

Good. I thought about that, too.

> > But, perhaps we should consider removing this option entirely. It is
> > the only one with a potentially serious security exposure. The others
> > at worst allow Denial of Service attacks.
>
> I hate allcaps too. Maybe you should just use a shell script wrapper
> like (untested):
>
> ----
> if echo uname -r |grep '^2\.4\.' ; then
> jackstart $@
> else
> jackd $@
> fi
> ----

I am willing to do that if the kernel developers think it better.

It recently occurred to me that jackstart might be able to detect this
situation and exec jackd, anyway. (AFAICT, the only reasonably
POSIX-compliant method for detecting that a process has the
"appropriate permission" to do something is trying it to see whether
it returns EPERM.)

Thanks for helping...
--
joq

2004-09-17 07:05:39

by torbenh

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Thu, Sep 16, 2004 at 01:27:02PM -0500, Jack O'Quin wrote:
>
> I am willing to do that if the kernel developers think it better.
>
> It recently occurred to me that jackstart might be able to detect this
> situation and exec jackd, anyway. (AFAICT, the only reasonably
> POSIX-compliant method for detecting that a process has the
> "appropriate permission" to do something is trying it to see whether
> it returns EPERM.)

how should jackstart detect the situation ?
its running SUID root and is allowed to do everything.

>
> Thanks for helping...
> --
> joq
>

--
torben Hohn
http://galan.sourceforge.net -- The graphical Audio language

2004-09-17 20:01:56

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

[email protected] writes:

> On Thu, Sep 16, 2004 at 01:27:02PM -0500, Jack O'Quin wrote:
> > It recently occurred to me that jackstart might be able to detect this
> > situation and exec jackd, anyway. (AFAICT, the only reasonably
> > POSIX-compliant method for detecting that a process has the
> > "appropriate permission" to do something is trying it to see whether
> > it returns EPERM.)
>
> how should jackstart detect the situation ?
> its running SUID root and is allowed to do everything.

I was thinking that it could drop root privileges and try creating a
realtime thread. But, then I realied it would be better (and simpler)
for `jackstart' to exec `jackd' unconditionally, even when the
required capabilities are not available. Let `jackd' figure out for
itself what it can actually do.

That is what I meant about trying the operation being the only
reliable test. Jackstart should not give up just because one
privilege mechanism is unavailable. It cannot know all the possible
reasons why jackd might or might not have access to realtime
resources. Its job is simply to pass the capabilities if they are
available.
--
joq

2004-09-20 20:21:36

by Jody McIntyre

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Fri, Sep 17, 2004 at 03:01:06PM -0500, Jack O'Quin wrote:

> I was thinking that it could drop root privileges and try creating a
> realtime thread. But, then I realied it would be better (and simpler)
> for `jackstart' to exec `jackd' unconditionally, even when the
> required capabilities are not available. Let `jackd' figure out for
> itself what it can actually do.

I agree. jackstart should always call jackd. I ran into a similar
problem a few weeks ago when I gave a demo on my laptop and didn't have
time to patch my kernel. I wasn't doing any serious recording so I
thought I'd run without -R. Of course, that didn't work until I changed
qjackctl to use 'jackd' as a command rather than 'jackstart'. This
could be a serious problem for a less experienced user.

Jody

> That is what I meant about trying the operation being the only
> reliable test. Jackstart should not give up just because one
> privilege mechanism is unavailable. It cannot know all the possible
> reasons why jackd might or might not have access to realtime
> resources. Its job is simply to pass the capabilities if they are
> available.
> --
> joq

--

2004-09-20 20:29:47

by Jody McIntyre

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Sun, Sep 12, 2004 at 01:46:18AM -0400, Lee Revell wrote:

> + Answer M to build realtime support as a Linux Security
> + Module. Answering Y to build realtime capabilities into the
> + kernel makes no sense.

Why does this make no sense?

I tried answering Y and it oopsed on boot. I'll try and track down/fix
what is happening later.

Jody

2004-09-21 00:11:55

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

Jody McIntyre <[email protected]> writes:

> On Sun, Sep 12, 2004 at 01:46:18AM -0400, Lee Revell wrote:
>
> > + Answer M to build realtime support as a Linux Security
> > + Module. Answering Y to build realtime capabilities into the
> > + kernel makes no sense.
>
> Why does this make no sense?

Before your /proc enhancement, it made no sense because there was no
way to set parameters. By default, the LSM does nothing. We should
change that comment now (as soon as it's working).

> I tried answering Y and it oopsed on boot. I'll try and track down/fix
> what is happening later.

Long ago, I built and ran it linked into the kernel (with different
parameter defaults), which worked at the time. It may matter how some
of the other security modules are configured. Perhaps some additional
Kconfig dependency checking would help. I'm not an expert at that.
--
joq

2004-09-21 07:49:09

by torbenh

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Mon, Sep 20, 2004 at 07:11:35PM -0500, Jack O'Quin wrote:
> Jody McIntyre <[email protected]> writes:
>
> > On Sun, Sep 12, 2004 at 01:46:18AM -0400, Lee Revell wrote:
> >
> > > + Answer M to build realtime support as a Linux Security
> > > + Module. Answering Y to build realtime capabilities into the
> > > + kernel makes no sense.
> >
> > Why does this make no sense?
>
> Before your /proc enhancement, it made no sense because there was no
> way to set parameters. By default, the LSM does nothing. We should
> change that comment now (as soon as it's working).

one can pass paremeters to the kernel on boot.
i think that the parameters get to the module somehow.
(the parameter stuff is handled by magic macros, which should now what
to do when not built as a module.
>
> > I tried answering Y and it oopsed on boot. I'll try and track down/fix
> > what is happening later.
>
> Long ago, I built and ran it linked into the kernel (with different
> parameter defaults), which worked at the time. It may matter how some
> of the other security modules are configured. Perhaps some additional
> Kconfig dependency checking would help. I'm not an expert at that.

i think jody will fix it.

> --
> joq
>

--
torben Hohn
http://galan.sourceforge.net -- The graphical Audio language

2004-09-30 21:16:24

by Jody McIntyre

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

I fixed the oops on boot by changing security_initcall() to late_initcall().
This moves initialization of the module to after /proc and sysctl is
setup.

This patch still includes allcaps, which should be removed before it is
merged.

The patch is now against 2.6.9-pre2-mm4.

Jody


The realtime-lsm Linux Security Module, written by Torben Hohn and Jack
O'Quin, selectively grants realtime capabilities to specific user groups
or applications. The typical use for this is low latency audio, and the
patch has been extensively field tested by Linux audio users. The
realtime LSM is a major improvement in security over the 2.4 capablities
patch and other workarounds like jackstart, which rely on CAP_SETPCAP.

Signed-Off-By: Lee Revell <[email protected]>
Signed-off-by: Jody McIntyre <[email protected]>

Index: linux/Documentation/realtime-lsm.txt
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/Documentation/realtime-lsm.txt 2004-09-30 14:10:24.000000000 -0400
@@ -0,0 +1,50 @@
+
+ Realtime Linux Security Module
+
+
+This Linux Security Module (LSM) enables realtime capabilities. It
+was written by Torben Hohn and Jack O'Quin, under the provisions of
+the GPL (see the COPYING file). We make no warranty concerning the
+safety, security or even stability of your system when using it. But,
+we will fix problems if you report them.
+
+Once the LSM has been installed and the kernel for which it was built
+is running, the root user can load it and pass parameters as follows:
+
+ # modprobe realtime any=1
+
+ Any program can request realtime privileges. This allows any local
+ user to crash the system by hogging the CPU in a tight loop or
+ locking down too much memory. But, it is simple to administer. :-)
+
+ # modprobe realtime gid=29
+
+ All users belonging to group 29 and programs that are setgid to that
+ group have realtime privileges. Use any group number you like.
+
+ # modprobe realtime mlock=0
+
+ Grants realtime scheduling privileges without the ability to lock
+ memory using mlock() or mlockall() system calls. This option can be
+ used in conjunction with any of the other options.
+
+ # modprobe realtime allcaps=1
+
+ Enables all capabilities, including CAP_SETPCAP. This is equivalent
+ to the 2.4 kernel capabilities patch. It is needed for root
+ programs to assign realtime capabilities to other processes. This
+ option can be used in conjunction with any of the other options.
+
+ The JACK Audio Connection Kit (jackit.sourceforge.net) includes a
+ `jackstart' program which uses CAP_SETPCAP to run the JACK daemon
+ and its clients with realtime capabilities.
+
+ There are serious security exposures with CAP_SETPCAP. If an
+ attacker manages to subvert some system daemon running with root
+ privileges, it can use this capability to deny needed privileges to
+ other root processes.
+
+All parameters except allcaps can be changed dynamically via the entries in
+/proc/sys/security/realtime.
+
+Jack O'Quin, [email protected]
Index: linux/security/Makefile
===================================================================
--- linux.orig/security/Makefile 2004-09-30 11:21:41.000000000 -0400
+++ linux/security/Makefile 2004-09-30 14:10:24.000000000 -0400
@@ -16,3 +16,4 @@ obj-$(CONFIG_SECURITY) += security.o d
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_REALTIME) += commoncap.o realtime.o
Index: linux/security/realtime.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/security/realtime.c 2004-09-30 14:10:24.000000000 -0400
@@ -0,0 +1,274 @@
+/*
+ * Realtime Capabilities Linux Security Module
+ *
+ * Copyright (C) 2003 Torben Hohn
+ * Copyright (C) 2003, 2004 Jack O'Quin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/ptrace.h>
+#include <linux/sysctl.h>
+
+#ifdef CONFIG_SECURITY
+
+#define RT_LSM "Realtime LSM " /* syslog module name prefix */
+#define RT_ERR "Realtime: " /* syslog error message prefix */
+
+#include <linux/vermagic.h>
+MODULE_INFO(vermagic,VERMAGIC_STRING);
+
+/* this is needed for the proc_dointvec_minmax for allowed GID */
+static int maxuid = 65535;
+static int minuid = -1;
+
+/* module parameters */
+static int any = 0; /* if TRUE, any process is realtime */
+MODULE_PARM(any, "i");
+MODULE_PARM_DESC(any, " grant realtime privileges to any process.");
+
+static int gid = -1; /* realtime group id, or NO_GROUP */
+MODULE_PARM(gid, "i");
+MODULE_PARM_DESC(gid, " the group ID with access to realtime privileges.");
+
+static int mlock = 1; /* enable mlock() privileges */
+MODULE_PARM(mlock, "i");
+MODULE_PARM_DESC(mlock, " enable memory locking privileges.");
+
+static int allcaps = 0; /* enable all capabilities */
+MODULE_PARM(allcaps, "i");
+MODULE_PARM_DESC(allcaps, " enable all capabilities, including CAP_SETPCAP.");
+
+static int gid_ok(int gid, int e_gid) {
+ int i;
+ int rt_ok = 0;
+
+ if (gid == -1)
+ return 0;
+
+ if ((gid == e_gid) || (gid == current->gid))
+ return 1;
+
+ get_group_info(current->group_info);
+ for (i = 0; i < current->group_info->ngroups; ++i) {
+ if (gid == GROUP_AT(current->group_info, i)) {
+ rt_ok = 1;
+ break;
+ }
+ }
+ put_group_info(current->group_info);
+
+ return rt_ok;
+}
+
+int realtime_bprm_set_security(struct linux_binprm *bprm)
+{
+ /* Copied from security/commoncap.c: cap_bprm_set_security()... */
+ /* Copied from fs/exec.c:prepare_binprm. */
+ /* We don't have VFS support for capabilities yet */
+ cap_clear(bprm->cap_inheritable);
+ cap_clear(bprm->cap_permitted);
+ cap_clear(bprm->cap_effective);
+
+ /* If a non-zero `any' parameter was specified, we grant
+ * realtime privileges to every process. If the `gid'
+ * parameter was specified and it matches the group id of the
+ * executable, of the current process or any supplementary
+ * groups, we grant realtime capabilites.
+ */
+
+ if (any || gid_ok(gid, bprm->e_gid)) {
+ cap_raise(bprm->cap_effective, CAP_SYS_NICE);
+ cap_raise(bprm->cap_permitted, CAP_SYS_NICE);
+ if (mlock) {
+ cap_raise(bprm->cap_effective, CAP_IPC_LOCK);
+ cap_raise(bprm->cap_permitted, CAP_IPC_LOCK);
+ cap_raise(bprm->cap_effective,
+ CAP_SYS_RESOURCE);
+ cap_raise(bprm->cap_permitted,
+ CAP_SYS_RESOURCE);
+ }
+ }
+
+ /* To support inheritance of root-permissions and suid-root
+ * executables under compatibility mode, we raise all three
+ * capability sets for the file.
+ *
+ * If only the real uid is 0, we only raise the inheritable
+ * and permitted sets of the executable file.
+ */
+
+ if (bprm->e_uid == 0 || current->uid == 0) {
+ cap_set_full(bprm->cap_inheritable);
+ cap_set_full(bprm->cap_permitted);
+ }
+ if (bprm->e_uid == 0)
+ cap_set_full(bprm->cap_effective);
+
+ return 0;
+}
+
+static struct security_operations capability_ops = {
+ .ptrace = cap_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+ .bprm_apply_creds = cap_bprm_apply_creds,
+ .bprm_set_security = realtime_bprm_set_security,
+ .bprm_secureexec = cap_bprm_secureexec,
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+ .syslog = cap_syslog,
+ .vm_enough_memory = cap_vm_enough_memory,
+};
+
+#define MY_NAME __stringify(KBUILD_MODNAME)
+
+static ctl_table realtime_table[] =
+{
+ { .ctl_name = 1,
+ .procname = "any",
+ .data = &any,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { .ctl_name = 2,
+ .procname = "gid",
+ .data = &gid,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = &minuid,
+ .extra2 = &maxuid
+ },
+ { .ctl_name = 3,
+ .procname = "mlock",
+ .data = &mlock,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { }
+};
+
+static ctl_table realtime_root_table[] =
+{
+ { .ctl_name = SECURITY_REALTIME,
+ .procname = "realtime",
+ .mode = 0555,
+ .child = realtime_table },
+ { }
+};
+
+static ctl_table security_root_table[] =
+{
+ { .ctl_name = CTL_SECURITY,
+ .procname = "security",
+ .mode = 0555,
+ .child = realtime_root_table },
+ { }
+};
+
+static struct ctl_table_header *sysctl_header;
+
+static void __exit exit_sysctl(void)
+{
+ unregister_sysctl_table(sysctl_header);
+}
+
+static int secondary; /* flag to keep track of how we were registered */
+static kernel_cap_t cap_bset_save; /* place to save cap-bound */
+
+static void __exit exit_security(void)
+{
+ cap_bset = cap_bset_save; /* restore cap-bound */
+
+ /* remove ourselves from the security framework */
+ if (secondary) {
+ if (mod_unreg_security(MY_NAME, &capability_ops))
+ printk(KERN_INFO RT_ERR "Failure unregistering "
+ "capabilities with primary module.\n");
+
+ } else if (unregister_security(&capability_ops)) {
+ printk(KERN_INFO RT_ERR
+ "Failure unregistering capabilities with the kernel\n");
+ }
+ printk(KERN_INFO "Realtime Capability LSM exiting\n");
+}
+
+static int __init capability_init(void)
+{
+ /* register ourselves with the security framework */
+ if (register_security(&capability_ops)) {
+
+ /* try registering with primary module */
+ if (mod_reg_security(MY_NAME, &capability_ops)) {
+ printk(KERN_INFO RT_ERR "Failure registering "
+ "capabilities with primary security module.\n");
+ printk(KERN_INFO RT_ERR "Is kernel configured "
+ "with CONFIG_SECURITY_CAPABILITIES=m?\n");
+ return -EINVAL;
+ }
+ secondary = 1;
+ }
+
+ cap_bset_save = cap_bset; /* save cap-bound */
+
+ sysctl_header = register_sysctl_table(security_root_table, 0);
+ if (!sysctl_header) {
+ exit_security();
+ return -ENOMEM;
+ }
+
+ if (allcaps) {
+ cap_bset = to_cap_t(~0);
+ printk(KERN_INFO RT_LSM "enabling all capabilities\n");
+ }
+
+ if (any)
+ printk(KERN_INFO RT_LSM
+ "initialized (all groups, mlock=%d)\n", mlock);
+ else if (gid == -1)
+ printk(KERN_INFO RT_LSM
+ "initialized (no groups, mlock=%d)\n", mlock);
+ else
+ printk(KERN_INFO RT_LSM
+ "initialized (group %d, mlock=%d)\n", gid, mlock);
+
+ return 0;
+}
+
+static void __exit capability_exit(void)
+{
+ exit_sysctl();
+ exit_security();
+}
+
+late_initcall(capability_init);
+module_exit(capability_exit);
+
+MODULE_DESCRIPTION("Realtime Capabilities Security Module");
+MODULE_LICENSE("GPL");
+
+#endif /* CONFIG_SECURITY */
Index: linux/include/linux/sysctl.h
===================================================================
--- linux.orig/include/linux/sysctl.h 2004-09-30 11:21:40.000000000 -0400
+++ linux/include/linux/sysctl.h 2004-09-30 14:10:24.000000000 -0400
@@ -61,7 +61,14 @@ enum
CTL_DEV=7, /* Devices */
CTL_BUS=8, /* Busses */
CTL_ABI=9, /* Binary emulation */
- CTL_CPU=10 /* CPU stuff (speed scaling, etc) */
+ CTL_CPU=10, /* CPU stuff (speed scaling, etc) */
+ CTL_SECURITY=11 /* Security modules */
+};
+
+/* CTL_SECURITY names: */
+enum
+{
+ SECURITY_REALTIME=1 /* Realtime LSM */
};

/* CTL_BUS names: */
Index: linux/security/Kconfig
===================================================================
--- linux.orig/security/Kconfig 2004-09-30 11:21:41.000000000 -0400
+++ linux/security/Kconfig 2004-09-30 14:10:24.000000000 -0400
@@ -73,6 +73,17 @@ config SECURITY_ROOTPLUG

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

+config SECURITY_REALTIME
+ tristate "Realtime Capabilities"
+ depends on SECURITY && SECURITY_CAPABILITIES!=y
+ default n
+ help
+ This module selectively grants realtime privileges
+ controlled by load-time parameters and
+ /proc/sys/security/realtime.
+
+ If you are unsure how to answer this question, answer N.
+
source security/selinux/Kconfig

endmenu

2004-09-30 21:53:43

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Thu, 2004-09-30 at 17:14, Jody McIntyre wrote:
> I fixed the oops on boot by changing security_initcall() to late_initcall().
> This moves initialization of the module to after /proc and sysctl is
> setup.
>
> This patch still includes allcaps, which should be removed before it is
> merged.

Another issue that was raised was that the mlock stuff is also
unnecessary, because rlimits can do this now. Is this the case?

Lee

2004-10-01 00:36:58

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

Lee Revell <[email protected]> writes:

> Another issue that was raised was that the mlock stuff is also
> unnecessary, because rlimits can do this now. Is this the case?

I don't know. The idea was not explained in enough detail for me to
understand if it would be simple enough to administer. Where can I
find out more?

Does this somehow explain the need for CAP_SYS_RESOURCE when calling
mlockall()? Comments in capability.h seem to imply that only
CAP_IPC_LOCK is required, which is not true. I never found any
explicit CAP_SYS_RESOURCE test in mm/mlock.c, though it does check
`rlim[RLIMIT_MEMLOCK].rlim_cur'.
--
joq

2004-10-01 01:20:59

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

* Jack O'Quin ([email protected]) wrote:
> Lee Revell <[email protected]> writes:
>
> > Another issue that was raised was that the mlock stuff is also
> > unnecessary, because rlimits can do this now. Is this the case?
>
> I don't know. The idea was not explained in enough detail for me to
> understand if it would be simple enough to administer. Where can I
> find out more?

This uses the basic rlimits infrastructure. You can manage it manually
in a shell with ulimit -l, or you can use pam (pam_limits) to configure
per uid limits. There's a pam doc that describes limits, and a manpage
for ulimit. It's really easy to use, and should eliminate the need for
the mlock part of that module.

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-10-01 04:05:32

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

Chris Wright <[email protected]> writes:

> This uses the basic rlimits infrastructure. You can manage it manually
> in a shell with ulimit -l, or you can use pam (pam_limits) to configure
> per uid limits. There's a pam doc that describes limits, and a manpage
> for ulimit. It's really easy to use, and should eliminate the need for
> the mlock part of that module.

Thanks for the pointer, Chris.

I'll see if I can figure out a way to make that useable for musicians.

The ulimit approach is way too cumbersome.

The pam_limits solution is not well-documented on my Debian system,
which doesn't even have a man page for /etc/security/limits.conf,
though the file has comments, now that I know where to look. PAM is
powerful and flexible, but "easy to use" is not a phrase that comes
readily to mind. :-)

The PAM approach would probably be workable for special-purpose audio
distributions like Planet CCRMA or DeMuDi. That still leaves all the
audio developers with a significant challenge trying to explain every
configuration step to all our other users. AFAICT, PAM configuration
is rather distribution-specific, so that could become a significant
burden.

It appears that a limits.conf line like this might work...

@audio - memlock 10000 # is there any way to say "unlimited"?

I'll experiment tomorrow to see if I can actually make this work.
--
joq

2004-10-01 20:46:20

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Fri, 2004-10-01 at 00:05, Jack O'Quin wrote:
> Chris Wright <[email protected]> writes:
>
> > This uses the basic rlimits infrastructure. You can manage it manually
> > in a shell with ulimit -l, or you can use pam (pam_limits) to configure
> > per uid limits. There's a pam doc that describes limits, and a manpage
> > for ulimit. It's really easy to use, and should eliminate the need for
> > the mlock part of that module.
>
> Thanks for the pointer, Chris.
>
> I'll see if I can figure out a way to make that useable for musicians.
>
> The ulimit approach is way too cumbersome.

Agreed. The whole point of getting realtime-lsm in the kernel is to
make it _easier_ to get a linux audio (or other realtime system) up and
running. Would it be feasible to use rlimits to let users run
SCHED_FIFO processes? The ulimit approach would probably be acceptable
if it subsumed all the functionality of the realtime-lsm module.

Lee

2004-10-01 21:33:02

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

* Lee Revell ([email protected]) wrote:
> On Fri, 2004-10-01 at 00:05, Jack O'Quin wrote:
> > The ulimit approach is way too cumbersome.
>
> Agreed. The whole point of getting realtime-lsm in the kernel is to
> make it _easier_ to get a linux audio (or other realtime system) up and
> running.

It's nice to have something that's easy to use, but that's not a great
justification for addition to the kernel. Esp. when there's a
functional userspace solution.

> Would it be feasible to use rlimits to let users run
> SCHED_FIFO processes?

No, it doesn't support that. I suppose it could, whether is should
is another matter.

> The ulimit approach would probably be acceptable
> if it subsumed all the functionality of the realtime-lsm module.

Hrm, I guess we'll have to agree to disagree. The whole point of the
mlock rlimits code is to enable this policy to be pushed to userspace.
A generic method of enabling capabilities is the best way to go, long
term. Any interest in pursuing that?

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-10-01 22:30:03

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Fri, 2004-10-01 at 17:23, Chris Wright wrote:
> * Lee Revell ([email protected]) wrote:
> > On Fri, 2004-10-01 at 00:05, Jack O'Quin wrote:
> > > The ulimit approach is way too cumbersome.
> >
> > Agreed. The whole point of getting realtime-lsm in the kernel is to
> > make it _easier_ to get a linux audio (or other realtime system) up and
> > running.
>
> It's nice to have something that's easy to use, but that's not a great
> justification for addition to the kernel. Esp. when there's a
> functional userspace solution.
>

OK, poor choice of words. Correctness of course comes before ease of
use. I believe the realtime-lsm module satisfies both requirements.

> > The ulimit approach would probably be acceptable
> > if it subsumed all the functionality of the realtime-lsm module.
>
> Hrm, I guess we'll have to agree to disagree. The whole point of the
> mlock rlimits code is to enable this policy to be pushed to userspace.
> A generic method of enabling capabilities is the best way to go, long
> term. Any interest in pursuing that?

I did not mean to imply that I disagree with the realtime-lsm approach.
Obviously some kernel support is required, and realtime-lsm seems to
solve the problem with the minimum possible change to the kernel. And
above all it is a proven working solution that has been field tested for
months by many, many users.

Lee

2004-10-01 22:34:35

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

* Lee Revell ([email protected]) wrote:
> On Fri, 2004-10-01 at 17:23, Chris Wright wrote:
> > It's nice to have something that's easy to use, but that's not a great
> > justification for addition to the kernel. Esp. when there's a
> > functional userspace solution.
>
> OK, poor choice of words. Correctness of course comes before ease of
> use. I believe the realtime-lsm module satisfies both requirements.

I agree with that. That's not my objection. It's about pushing code
(albeit it's small and non-invasive) into the kernel that can be done in
userspace, that's all.

> > > The ulimit approach would probably be acceptable
> > > if it subsumed all the functionality of the realtime-lsm module.
> >
> > Hrm, I guess we'll have to agree to disagree. The whole point of the
> > mlock rlimits code is to enable this policy to be pushed to userspace.
> > A generic method of enabling capabilities is the best way to go, long
> > term. Any interest in pursuing that?
>
> I did not mean to imply that I disagree with the realtime-lsm approach.
> Obviously some kernel support is required, and realtime-lsm seems to
> solve the problem with the minimum possible change to the kernel. And
> above all it is a proven working solution that has been field tested for
> months by many, many users.

Clearly it's useful for the audio folks. Whether it's the right thing
to go into the kernel is all that's in question here. Do we agree it's
a stopgap measure making up for lack of a better general solution?

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-10-01 22:35:52

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Fri, 2004-10-01 at 18:27, Chris Wright wrote:
> * Lee Revell ([email protected]) wrote:
> > On Fri, 2004-10-01 at 17:23, Chris Wright wrote:
> > > It's nice to have something that's easy to use, but that's not a great
> > > justification for addition to the kernel. Esp. when there's a
> > > functional userspace solution.
> >
> > OK, poor choice of words. Correctness of course comes before ease of
> > use. I believe the realtime-lsm module satisfies both requirements.
>
> I agree with that. That's not my objection. It's about pushing code
> (albeit it's small and non-invasive) into the kernel that can be done in
> userspace, that's all.
>

How do you envision this working? I am sure it's possible, I think I am
just not seeing how it would be different in practice.

> > > > The ulimit approach would probably be acceptable
> > > > if it subsumed all the functionality of the realtime-lsm module.
> > >
> > > Hrm, I guess we'll have to agree to disagree. The whole point of the
> > > mlock rlimits code is to enable this policy to be pushed to userspace.
> > > A generic method of enabling capabilities is the best way to go, long
> > > term. Any interest in pursuing that?
> >
> > I did not mean to imply that I disagree with the realtime-lsm approach.
> > Obviously some kernel support is required, and realtime-lsm seems to
> > solve the problem with the minimum possible change to the kernel. And
> > above all it is a proven working solution that has been field tested for
> > months by many, many users.
>
> Clearly it's useful for the audio folks. Whether it's the right thing
> to go into the kernel is all that's in question here. Do we agree it's
> a stopgap measure making up for lack of a better general solution?
>

See above, no argument here from me.

Lee

2004-10-01 22:48:25

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

* Lee Revell ([email protected]) wrote:
> On Fri, 2004-10-01 at 18:27, Chris Wright wrote:
> > I agree with that. That's not my objection. It's about pushing code
> > (albeit it's small and non-invasive) into the kernel that can be done in
> > userspace, that's all.
>
> How do you envision this working? I am sure it's possible, I think I am
> just not seeing how it would be different in practice.

As of now, the only practical part to move out is just that tiny
mlock bit. Using pam_limits seems the best choice there. This burdens
the audio folks with a documentation task (describing not only how
to turn this rlimits feature on properly, although that'd be welcome
since the docs in that area are lacking, but also doc for the module
re: SCHED_FIFO). A general solution is pam_cap, and making capabilities
inherit in a sane way (Andy L. and I have code to move in that direction).
One step shy of that, is extend what you've done across the capability
set, so that it could solve problems similar to yours but with different
cap requirements. Pushing more bits into rlimits is possible as well,
but could get unruly.

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-10-05 04:01:12

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

Jody McIntyre <[email protected]> writes:

> This patch still includes allcaps, which should be removed before it is
> merged.

The `allcaps' option is removed in this version, documentation
updated, plus some minor comment changes.

> The patch is now against 2.6.9-pre2-mm4.

This patch was diff'ed against 2.6.8.1. Some of the offsets in
2.6.9-pre2-mm4 were slightly different, but the patch applied
correctly anyway. I think it will work fine either way.

> The realtime-lsm Linux Security Module, written by Torben Hohn and Jack
> O'Quin, selectively grants realtime capabilities to specific user groups
> or applications. The typical use for this is low latency audio, and the
> patch has been extensively field tested by Linux audio users. The
> realtime LSM is a major improvement in security over the 2.4 capablities
> patch and other workarounds like jackstart, which rely on CAP_SETPCAP.
>
> Signed-Off-By: Lee Revell <[email protected]>
> Signed-off-by: Jody McIntyre <[email protected]>

Signed-off-by: Jack O'Quin <[email protected]>

diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/Documentation/realtime-lsm.txt linux-2.6.8.1-rt02/Documentation/realtime-lsm.txt
--- linux-2.6.8.1/Documentation/realtime-lsm.txt Wed Dec 31 18:00:00 1969
+++ linux-2.6.8.1-rt02/Documentation/realtime-lsm.txt Mon Oct 4 21:38:26 2004
@@ -0,0 +1,38 @@
+
+ Realtime Linux Security Module
+
+
+This Linux Security Module (LSM) enables realtime capabilities. It
+was written by Torben Hohn and Jack O'Quin, under the provisions of
+the GPL (see the COPYING file). We make no warranty concerning the
+safety, security or even stability of your system when using it. But,
+we will fix problems if you report them.
+
+Once the LSM has been installed and the kernel for which it was built
+is running, the root user can load it and pass parameters as follows:
+
+ # modprobe realtime any=1
+
+ Any program can request realtime privileges. This allows any local
+ user to crash the system by hogging the CPU in a tight loop or
+ locking down too much memory. But, it is simple to administer. :-)
+
+ # modprobe realtime gid=29
+
+ All users belonging to group 29 and programs that are setgid to that
+ group have realtime privileges. Use any group number you like. A
+ `gid' of -1 disables group access.
+
+ # modprobe realtime mlock=0
+
+ Grants realtime scheduling privileges without the ability to lock
+ memory using mlock() or mlockall() system calls. This option can be
+ used in conjunction with any of the other options.
+
+Parameters can be changed dynamically via /proc/sys/security/realtime:
+
+ # sysctl -w security/realtime/any=0
+ # sysctl -w security/realtime/gid=29
+ # sysctl -w security/realtime/mlock=1
+
+Jack O'Quin, [email protected]
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/include/linux/sysctl.h linux-2.6.8.1-rt02/include/linux/sysctl.h
--- linux-2.6.8.1/include/linux/sysctl.h Sat Aug 14 05:55:33 2004
+++ linux-2.6.8.1-rt02/include/linux/sysctl.h Sun Oct 3 10:56:16 2004
@@ -61,7 +61,14 @@
CTL_DEV=7, /* Devices */
CTL_BUS=8, /* Busses */
CTL_ABI=9, /* Binary emulation */
- CTL_CPU=10 /* CPU stuff (speed scaling, etc) */
+ CTL_CPU=10, /* CPU stuff (speed scaling, etc) */
+ CTL_SECURITY=11 /* Security modules */
+};
+
+/* CTL_SECURITY names: */
+enum
+{
+ SECURITY_REALTIME=1 /* Realtime LSM */
};

/* CTL_BUS names: */
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/security/Kconfig linux-2.6.8.1-rt02/security/Kconfig
--- linux-2.6.8.1/security/Kconfig Sat Aug 14 05:55:47 2004
+++ linux-2.6.8.1-rt02/security/Kconfig Sun Oct 3 10:56:17 2004
@@ -44,6 +44,17 @@

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

+config SECURITY_REALTIME
+ tristate "Realtime Capabilities"
+ depends on SECURITY && SECURITY_CAPABILITIES!=y
+ default n
+ help
+ This module selectively grants realtime privileges
+ controlled by load-time parameters and
+ /proc/sys/security/realtime.
+
+ If you are unsure how to answer this question, answer N.
+
source security/selinux/Kconfig

endmenu
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/security/Makefile linux-2.6.8.1-rt02/security/Makefile
--- linux-2.6.8.1/security/Makefile Sat Aug 14 05:55:48 2004
+++ linux-2.6.8.1-rt02/security/Makefile Sun Oct 3 10:56:16 2004
@@ -15,3 +15,4 @@
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_REALTIME) += commoncap.o realtime.o
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/security/realtime.c linux-2.6.8.1-rt02/security/realtime.c
--- linux-2.6.8.1/security/realtime.c Wed Dec 31 18:00:00 1969
+++ linux-2.6.8.1-rt02/security/realtime.c Mon Oct 4 21:35:41 2004
@@ -0,0 +1,267 @@
+/*
+ * Realtime Capabilities Linux Security Module
+ *
+ * Copyright (C) 2003 Torben Hohn
+ * Copyright (C) 2003, 2004 Jack O'Quin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/ptrace.h>
+#include <linux/sysctl.h>
+
+#ifdef CONFIG_SECURITY
+
+#define RT_LSM "Realtime LSM " /* syslog module name prefix */
+#define RT_ERR "Realtime: " /* syslog error message prefix */
+
+#include <linux/vermagic.h>
+MODULE_INFO(vermagic,VERMAGIC_STRING);
+
+/* this is needed for the proc_dointvec_minmax for allowed GID */
+static int maxuid = 65535;
+static int minuid = -1;
+
+/* module parameters
+ *
+ * These values could change at any time due to some process writing
+ * a new value to /proc/sys/security/realtime. This is OK, because
+ * each is referenced only once in each function call. Nothing
+ * depends on parameters having the same value every time.
+ */
+static int any = 0; /* if TRUE, any process is realtime */
+MODULE_PARM(any, "i");
+MODULE_PARM_DESC(any, " grant realtime privileges to any process.");
+
+static int gid = -1; /* realtime group id, or NO_GROUP */
+MODULE_PARM(gid, "i");
+MODULE_PARM_DESC(gid, " the group ID with access to realtime privileges.");
+
+static int mlock = 1; /* enable mlock() privileges */
+MODULE_PARM(mlock, "i");
+MODULE_PARM_DESC(mlock, " enable memory locking privileges.");
+
+/* helper function for testing group membership */
+static inline int gid_ok(int gid, int e_gid) {
+ int i;
+ int rt_ok = 0;
+
+ if (gid == -1)
+ return 0;
+
+ if ((gid == e_gid) || (gid == current->gid))
+ return 1;
+
+ get_group_info(current->group_info);
+ for (i = 0; i < current->group_info->ngroups; ++i) {
+ if (gid == GROUP_AT(current->group_info, i)) {
+ rt_ok = 1;
+ break;
+ }
+ }
+ put_group_info(current->group_info);
+
+ return rt_ok;
+}
+
+int realtime_bprm_set_security(struct linux_binprm *bprm)
+{
+ /* Copied from security/commoncap.c: cap_bprm_set_security()... */
+ /* Copied from fs/exec.c:prepare_binprm. */
+ /* We don't have VFS support for capabilities yet */
+ cap_clear(bprm->cap_inheritable);
+ cap_clear(bprm->cap_permitted);
+ cap_clear(bprm->cap_effective);
+
+ /* If a non-zero `any' parameter was specified, we grant
+ * realtime privileges to every process. If the `gid'
+ * parameter was specified and it matches the group id of the
+ * executable, of the current process or any supplementary
+ * groups, we grant realtime capabilites.
+ */
+
+ if (any || gid_ok(gid, bprm->e_gid)) {
+ cap_raise(bprm->cap_effective, CAP_SYS_NICE);
+ cap_raise(bprm->cap_permitted, CAP_SYS_NICE);
+ if (mlock) {
+ cap_raise(bprm->cap_effective, CAP_IPC_LOCK);
+ cap_raise(bprm->cap_permitted, CAP_IPC_LOCK);
+ cap_raise(bprm->cap_effective,
+ CAP_SYS_RESOURCE);
+ cap_raise(bprm->cap_permitted,
+ CAP_SYS_RESOURCE);
+ }
+ }
+
+ /* To support inheritance of root-permissions and suid-root
+ * executables under compatibility mode, we raise all three
+ * capability sets for the file.
+ *
+ * If only the real uid is 0, we only raise the inheritable
+ * and permitted sets of the executable file.
+ */
+
+ if (bprm->e_uid == 0 || current->uid == 0) {
+ cap_set_full(bprm->cap_inheritable);
+ cap_set_full(bprm->cap_permitted);
+ }
+ if (bprm->e_uid == 0)
+ cap_set_full(bprm->cap_effective);
+
+ return 0;
+}
+
+static struct security_operations capability_ops = {
+ .ptrace = cap_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+ .bprm_apply_creds = cap_bprm_apply_creds,
+ .bprm_set_security = realtime_bprm_set_security,
+ .bprm_secureexec = cap_bprm_secureexec,
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+ .syslog = cap_syslog,
+ .vm_enough_memory = cap_vm_enough_memory,
+};
+
+#define MY_NAME __stringify(KBUILD_MODNAME)
+
+static ctl_table realtime_table[] =
+{
+ { .ctl_name = 1,
+ .procname = "any",
+ .data = &any,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { .ctl_name = 2,
+ .procname = "gid",
+ .data = &gid,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = &minuid,
+ .extra2 = &maxuid
+ },
+ { .ctl_name = 3,
+ .procname = "mlock",
+ .data = &mlock,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { }
+};
+
+static ctl_table realtime_root_table[] =
+{
+ { .ctl_name = SECURITY_REALTIME,
+ .procname = "realtime",
+ .mode = 0555,
+ .child = realtime_table },
+ { }
+};
+
+static ctl_table security_root_table[] =
+{
+ { .ctl_name = CTL_SECURITY,
+ .procname = "security",
+ .mode = 0555,
+ .child = realtime_root_table },
+ { }
+};
+
+static struct ctl_table_header *sysctl_header;
+
+static void __exit exit_sysctl(void)
+{
+ unregister_sysctl_table(sysctl_header);
+}
+
+static int secondary; /* flag to keep track of how we were registered */
+
+static void __exit exit_security(void)
+{
+ /* remove ourselves from the security framework */
+ if (secondary) {
+ if (mod_unreg_security(MY_NAME, &capability_ops))
+ printk(KERN_INFO RT_ERR "Failure unregistering "
+ "capabilities with primary module.\n");
+
+ } else if (unregister_security(&capability_ops)) {
+ printk(KERN_INFO RT_ERR
+ "Failure unregistering capabilities with the kernel\n");
+ }
+ printk(KERN_INFO "Realtime Capability LSM exiting\n");
+}
+
+static int __init capability_init(void)
+{
+ /* register ourselves with the security framework */
+ if (register_security(&capability_ops)) {
+
+ /* try registering with primary module */
+ if (mod_reg_security(MY_NAME, &capability_ops)) {
+ printk(KERN_INFO RT_ERR "Failure registering "
+ "capabilities with primary security module.\n");
+ printk(KERN_INFO RT_ERR "Is kernel configured "
+ "with CONFIG_SECURITY_CAPABILITIES=m?\n");
+ return -EINVAL;
+ }
+ secondary = 1;
+ }
+
+ sysctl_header = register_sysctl_table(security_root_table, 0);
+ if (!sysctl_header) {
+ exit_security();
+ return -ENOMEM;
+ }
+
+ if (any)
+ printk(KERN_INFO RT_LSM
+ "initialized (all groups, mlock=%d)\n", mlock);
+ else if (gid == -1)
+ printk(KERN_INFO RT_LSM
+ "initialized (no groups, mlock=%d)\n", mlock);
+ else
+ printk(KERN_INFO RT_LSM
+ "initialized (group %d, mlock=%d)\n", gid, mlock);
+
+ return 0;
+}
+
+static void __exit capability_exit(void)
+{
+ exit_sysctl();
+ exit_security();
+}
+
+late_initcall(capability_init);
+module_exit(capability_exit);
+
+MODULE_DESCRIPTION("Realtime Capabilities Security Module");
+MODULE_LICENSE("GPL");
+
+#endif /* CONFIG_SECURITY */

--
joq

2004-10-05 05:55:55

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

Chris Wright <[email protected]> writes:

> * Lee Revell ([email protected]) wrote:
> > OK, poor choice of words. Correctness of course comes before ease of
> > use. I believe the realtime-lsm module satisfies both requirements.
>
> I agree with that. That's not my objection. It's about pushing code
> (albeit it's small and non-invasive) into the kernel that can be done in
> userspace, that's all.

> > > Hrm, I guess we'll have to agree to disagree. The whole point of the
> > > mlock rlimits code is to enable this policy to be pushed to userspace.
> > > A generic method of enabling capabilities is the best way to go, long
> > > term. Any interest in pursuing that?

None here. I prefer to spend my time on audio development than kernel
code. There are plenty of good kernel developers already.

I agree that a generic capabilities module would be nice to have,
mainly because of current difficulties with stacking multiple LSM's.
However, if there were a good stacking facility, then multiple,
simple, application-oriented modules like the realtime-lsm might be
even better in some respects.

> > I did not mean to imply that I disagree with the realtime-lsm approach.
> > Obviously some kernel support is required, and realtime-lsm seems to
> > solve the problem with the minimum possible change to the kernel. And
> > above all it is a proven working solution that has been field tested for
> > months by many, many users.
>
> Clearly it's useful for the audio folks. Whether it's the right thing
> to go into the kernel is all that's in question here. Do we agree it's
> a stopgap measure making up for lack of a better general solution?

Sure, I agree. But, I suspect that gap looks much larger from my
perspective than yours. :-)

We would never have developed this LSM had there not been a serious
need. Audio developers have been struggling for years with the need
to apply specialized kernel patches to get acceptable realtime
operation. Audio is very intolerant of realtime glitches. They cause
nasty pops in the output. And, large audio applications should not
run as `root'. The 2.4 "capabilities patch" was never a satisfactory
solution.

Thanks to the good work being done on 2.6, we are now close to being
able to do serious realtime work with standard kernels available
everwhere. The LSM framework is an important element of that
solution, with the realtime LSM a small but essential component,
because it makes these features available without excessive
administrative burden. Many musicians have a Mac or Windows
background. They are not willing to perform complex system
administration tasks to get good audio performance. PAM is great for
sophisticated sysadmins on shared systems. But, I seriously doubt
many musicians will be able to configure it correctly. For a
single-user Digital Audio Workstation it is overkill.

So, even if you do provide a more general solution, I will probably
have to continue supporting the realtime-lsm interface throughout the
2.6 kernel life-cycle, as there will be enough users for it to be a
defacto standard. If it is no longer needed in the 2.8 timeframe, I
can drop support then.

It's hard to say how many people use realtime-lsm right now.
SourceForge lists about 1500 source downloads over the last six
months. Binary copies are included in the most popular audio-oriented
distributions, including Planet CCRMA and DeMuDi. I guess there are
probably no more than a few thousand active users.

These are already enough that I feel committed to providing whatever
module updates are required for all official 2.6 kernel versions.
Including the LSM in the kernel would distribute it to more users. It
would also simplify maintenance slightly. I currently maintain a
single source that works for all 2.6 versions. As a practical matter,
I may ignore some of the pre-2.6.6 issues in the next release.

Is that what you meant by stop-gap? :-)
--
joq

2004-10-07 23:58:33

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Tue, 2004-10-05 at 01:55, Jack O'Quin wrote:
> Thanks to the good work being done on 2.6, we are now close to being
> able to do serious realtime work with standard kernels available
> everwhere. The LSM framework is an important element of that
> solution, with the realtime LSM a small but essential component,
> because it makes these features available without excessive
> administrative burden.

Since no one has objected to any of Jack's points, and now that the
setpcap is gone, and with more audio users moving to 2.6+mm+VP every
day, I would like to ask that this go into -mm. Any objections?

Lee

2004-10-08 20:59:42

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Thu, 2004-10-07 at 19:51, Lee Revell wrote:
> On Tue, 2004-10-05 at 01:55, Jack O'Quin wrote:
> > Thanks to the good work being done on 2.6, we are now close to being
> > able to do serious realtime work with standard kernels available
> > everwhere. The LSM framework is an important element of that
> > solution, with the realtime LSM a small but essential component,
> > because it makes these features available without excessive
> > administrative burden.
>
> Since no one has objected to any of Jack's points, and now that the
> setpcap is gone, and with more audio users moving to 2.6+mm+VP every
> day, I would like to ask that this go into -mm. Any objections?
>

Oops, I just realized that this has some rejects now with -mm3 due to
the addition of the BSD jail LSM. Here's an updated patch, only
difference is line numbers.

Lee

Signed-Off-By: Lee Revell <[email protected]>
Signed-off-by: Jody McIntyre <[email protected]>
Signed-off-by: Jack O'Quin <[email protected]>

diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/Documentation/realtime-lsm.txt linux-2.6.8.1-rt02/Documentation/realtime-lsm.txt
--- linux-2.6.8.1/Documentation/realtime-lsm.txt Wed Dec 31 18:00:00 1969
+++ linux-2.6.8.1-rt02/Documentation/realtime-lsm.txt Mon Oct 4 21:38:26 2004
@@ -0,0 +1,38 @@
+
+ Realtime Linux Security Module
+
+
+This Linux Security Module (LSM) enables realtime capabilities. It
+was written by Torben Hohn and Jack O'Quin, under the provisions of
+the GPL (see the COPYING file). We make no warranty concerning the
+safety, security or even stability of your system when using it. But,
+we will fix problems if you report them.
+
+Once the LSM has been installed and the kernel for which it was built
+is running, the root user can load it and pass parameters as follows:
+
+ # modprobe realtime any=1
+
+ Any program can request realtime privileges. This allows any local
+ user to crash the system by hogging the CPU in a tight loop or
+ locking down too much memory. But, it is simple to administer. :-)
+
+ # modprobe realtime gid=29
+
+ All users belonging to group 29 and programs that are setgid to that
+ group have realtime privileges. Use any group number you like. A
+ `gid' of -1 disables group access.
+
+ # modprobe realtime mlock=0
+
+ Grants realtime scheduling privileges without the ability to lock
+ memory using mlock() or mlockall() system calls. This option can be
+ used in conjunction with any of the other options.
+
+Parameters can be changed dynamically via /proc/sys/security/realtime:
+
+ # sysctl -w security/realtime/any=0
+ # sysctl -w security/realtime/gid=29
+ # sysctl -w security/realtime/mlock=1
+
+Jack O'Quin, [email protected]
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/include/linux/sysctl.h linux-2.6.8.1-rt02/include/linux/sysctl.h
--- linux-2.6.8.1/include/linux/sysctl.h Sat Aug 14 05:55:33 2004
+++ linux-2.6.8.1-rt02/include/linux/sysctl.h Sun Oct 3 10:56:16 2004
@@ -61,7 +61,14 @@
CTL_DEV=7, /* Devices */
CTL_BUS=8, /* Busses */
CTL_ABI=9, /* Binary emulation */
- CTL_CPU=10 /* CPU stuff (speed scaling, etc) */
+ CTL_CPU=10, /* CPU stuff (speed scaling, etc) */
+ CTL_SECURITY=11 /* Security modules */
+};
+
+/* CTL_SECURITY names: */
+enum
+{
+ SECURITY_REALTIME=1 /* Realtime LSM */
};

/* CTL_BUS names: */
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/security/Kconfig linux-2.6.8.1-rt02/security/Kconfig
--- linux-2.6.8.1/security/Kconfig Sat Aug 14 05:55:47 2004
+++ linux-2.6.8.1-rt02/security/Kconfig Sun Oct 3 10:56:17 2004
@@ -84,6 +84,17 @@

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

+config SECURITY_REALTIME
+ tristate "Realtime Capabilities"
+ depends on SECURITY && SECURITY_CAPABILITIES!=y
+ default n
+ help
+ This module selectively grants realtime privileges
+ controlled by load-time parameters and
+ /proc/sys/security/realtime.
+
+ If you are unsure how to answer this question, answer N.
+
source security/selinux/Kconfig

config SECURITY_BSDJAIL
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/security/Makefile linux-2.6.8.1-rt02/security/Makefile
--- linux-2.6.8.1/security/Makefile Sat Aug 14 05:55:48 2004
+++ linux-2.6.8.1-rt02/security/Makefile Sun Oct 3 10:56:16 2004
@@ -18,3 +18,4 @@
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
obj-$(CONFIG_SECURITY_SECLVL) += seclvl.o
obj-$(CONFIG_SECURITY_BSDJAIL) += bsdjail.o
+obj-$(CONFIG_SECURITY_REALTIME) += commoncap.o realtime.o
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/security/realtime.c linux-2.6.8.1-rt02/security/realtime.c
--- linux-2.6.8.1/security/realtime.c Wed Dec 31 18:00:00 1969
+++ linux-2.6.8.1-rt02/security/realtime.c Mon Oct 4 21:35:41 2004
@@ -0,0 +1,267 @@
+/*
+ * Realtime Capabilities Linux Security Module
+ *
+ * Copyright (C) 2003 Torben Hohn
+ * Copyright (C) 2003, 2004 Jack O'Quin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/ptrace.h>
+#include <linux/sysctl.h>
+
+#ifdef CONFIG_SECURITY
+
+#define RT_LSM "Realtime LSM " /* syslog module name prefix */
+#define RT_ERR "Realtime: " /* syslog error message prefix */
+
+#include <linux/vermagic.h>
+MODULE_INFO(vermagic,VERMAGIC_STRING);
+
+/* this is needed for the proc_dointvec_minmax for allowed GID */
+static int maxuid = 65535;
+static int minuid = -1;
+
+/* module parameters
+ *
+ * These values could change at any time due to some process writing
+ * a new value to /proc/sys/security/realtime. This is OK, because
+ * each is referenced only once in each function call. Nothing
+ * depends on parameters having the same value every time.
+ */
+static int any = 0; /* if TRUE, any process is realtime */
+MODULE_PARM(any, "i");
+MODULE_PARM_DESC(any, " grant realtime privileges to any process.");
+
+static int gid = -1; /* realtime group id, or NO_GROUP */
+MODULE_PARM(gid, "i");
+MODULE_PARM_DESC(gid, " the group ID with access to realtime privileges.");
+
+static int mlock = 1; /* enable mlock() privileges */
+MODULE_PARM(mlock, "i");
+MODULE_PARM_DESC(mlock, " enable memory locking privileges.");
+
+/* helper function for testing group membership */
+static inline int gid_ok(int gid, int e_gid) {
+ int i;
+ int rt_ok = 0;
+
+ if (gid == -1)
+ return 0;
+
+ if ((gid == e_gid) || (gid == current->gid))
+ return 1;
+
+ get_group_info(current->group_info);
+ for (i = 0; i < current->group_info->ngroups; ++i) {
+ if (gid == GROUP_AT(current->group_info, i)) {
+ rt_ok = 1;
+ break;
+ }
+ }
+ put_group_info(current->group_info);
+
+ return rt_ok;
+}
+
+int realtime_bprm_set_security(struct linux_binprm *bprm)
+{
+ /* Copied from security/commoncap.c: cap_bprm_set_security()... */
+ /* Copied from fs/exec.c:prepare_binprm. */
+ /* We don't have VFS support for capabilities yet */
+ cap_clear(bprm->cap_inheritable);
+ cap_clear(bprm->cap_permitted);
+ cap_clear(bprm->cap_effective);
+
+ /* If a non-zero `any' parameter was specified, we grant
+ * realtime privileges to every process. If the `gid'
+ * parameter was specified and it matches the group id of the
+ * executable, of the current process or any supplementary
+ * groups, we grant realtime capabilites.
+ */
+
+ if (any || gid_ok(gid, bprm->e_gid)) {
+ cap_raise(bprm->cap_effective, CAP_SYS_NICE);
+ cap_raise(bprm->cap_permitted, CAP_SYS_NICE);
+ if (mlock) {
+ cap_raise(bprm->cap_effective, CAP_IPC_LOCK);
+ cap_raise(bprm->cap_permitted, CAP_IPC_LOCK);
+ cap_raise(bprm->cap_effective,
+ CAP_SYS_RESOURCE);
+ cap_raise(bprm->cap_permitted,
+ CAP_SYS_RESOURCE);
+ }
+ }
+
+ /* To support inheritance of root-permissions and suid-root
+ * executables under compatibility mode, we raise all three
+ * capability sets for the file.
+ *
+ * If only the real uid is 0, we only raise the inheritable
+ * and permitted sets of the executable file.
+ */
+
+ if (bprm->e_uid == 0 || current->uid == 0) {
+ cap_set_full(bprm->cap_inheritable);
+ cap_set_full(bprm->cap_permitted);
+ }
+ if (bprm->e_uid == 0)
+ cap_set_full(bprm->cap_effective);
+
+ return 0;
+}
+
+static struct security_operations capability_ops = {
+ .ptrace = cap_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+ .bprm_apply_creds = cap_bprm_apply_creds,
+ .bprm_set_security = realtime_bprm_set_security,
+ .bprm_secureexec = cap_bprm_secureexec,
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+ .syslog = cap_syslog,
+ .vm_enough_memory = cap_vm_enough_memory,
+};
+
+#define MY_NAME __stringify(KBUILD_MODNAME)
+
+static ctl_table realtime_table[] =
+{
+ { .ctl_name = 1,
+ .procname = "any",
+ .data = &any,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { .ctl_name = 2,
+ .procname = "gid",
+ .data = &gid,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = &minuid,
+ .extra2 = &maxuid
+ },
+ { .ctl_name = 3,
+ .procname = "mlock",
+ .data = &mlock,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { }
+};
+
+static ctl_table realtime_root_table[] =
+{
+ { .ctl_name = SECURITY_REALTIME,
+ .procname = "realtime",
+ .mode = 0555,
+ .child = realtime_table },
+ { }
+};
+
+static ctl_table security_root_table[] =
+{
+ { .ctl_name = CTL_SECURITY,
+ .procname = "security",
+ .mode = 0555,
+ .child = realtime_root_table },
+ { }
+};
+
+static struct ctl_table_header *sysctl_header;
+
+static void __exit exit_sysctl(void)
+{
+ unregister_sysctl_table(sysctl_header);
+}
+
+static int secondary; /* flag to keep track of how we were registered */
+
+static void __exit exit_security(void)
+{
+ /* remove ourselves from the security framework */
+ if (secondary) {
+ if (mod_unreg_security(MY_NAME, &capability_ops))
+ printk(KERN_INFO RT_ERR "Failure unregistering "
+ "capabilities with primary module.\n");
+
+ } else if (unregister_security(&capability_ops)) {
+ printk(KERN_INFO RT_ERR
+ "Failure unregistering capabilities with the kernel\n");
+ }
+ printk(KERN_INFO "Realtime Capability LSM exiting\n");
+}
+
+static int __init capability_init(void)
+{
+ /* register ourselves with the security framework */
+ if (register_security(&capability_ops)) {
+
+ /* try registering with primary module */
+ if (mod_reg_security(MY_NAME, &capability_ops)) {
+ printk(KERN_INFO RT_ERR "Failure registering "
+ "capabilities with primary security module.\n");
+ printk(KERN_INFO RT_ERR "Is kernel configured "
+ "with CONFIG_SECURITY_CAPABILITIES=m?\n");
+ return -EINVAL;
+ }
+ secondary = 1;
+ }
+
+ sysctl_header = register_sysctl_table(security_root_table, 0);
+ if (!sysctl_header) {
+ exit_security();
+ return -ENOMEM;
+ }
+
+ if (any)
+ printk(KERN_INFO RT_LSM
+ "initialized (all groups, mlock=%d)\n", mlock);
+ else if (gid == -1)
+ printk(KERN_INFO RT_LSM
+ "initialized (no groups, mlock=%d)\n", mlock);
+ else
+ printk(KERN_INFO RT_LSM
+ "initialized (group %d, mlock=%d)\n", gid, mlock);
+
+ return 0;
+}
+
+static void __exit capability_exit(void)
+{
+ exit_sysctl();
+ exit_security();
+}
+
+late_initcall(capability_init);
+module_exit(capability_exit);
+
+MODULE_DESCRIPTION("Realtime Capabilities Security Module");
+MODULE_LICENSE("GPL");
+
+#endif /* CONFIG_SECURITY */

2004-10-08 21:17:31

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

Lee Revell <[email protected]> wrote:
>
> Here's an updated patch, only
> difference is line numbers.

Nice patch. Wanna tell me something about what it's for?

I haven't been following the "Realtime LSM" thread and I'd rather not have to
prepare a description of your work for you.

2004-10-08 21:22:48

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Fri, 2004-10-08 at 17:21, Andrew Morton wrote:
> Lee Revell <[email protected]> wrote:
> >
> > Here's an updated patch, only
> > difference is line numbers.
>
> Nice patch. Wanna tell me something about what it's for?
>
> I haven't been following the "Realtime LSM" thread and I'd rather not have to
> prepare a description of your work for you.
>

Oh, sorry. Here's the description from my original post:

The realtime-lsm Linux Security Module, written by Torben Hohn and Jack
O'Quin, selectively grants realtime capabilities to specific user groups
or applications. The typical use for this is low latency audio, and the
patch has been extensively field tested by Linux audio users. The
realtime LSM is a major improvement in security over the 2.4 capablities
patch and other workarounds like jackstart, which rely on CAP_SETPCAP.

This has been extensively field tested, and undeniably satisfies a
demand (unlike some other LSMs posted lately). Here is the the author's
more detailed explanation:

"We would never have developed this LSM had there not been a serious
need. Audio developers have been struggling for years with the need
to apply specialized kernel patches to get acceptable realtime
operation. Audio is very intolerant of realtime glitches. They cause
nasty pops in the output. And, large audio applications should not
run as `root'. The 2.4 "capabilities patch" was never a satisfactory
solution.

Thanks to the good work being done on 2.6, we are now close to being
able to do serious realtime work with standard kernels available
everwhere. The LSM framework is an important element of that
solution, with the realtime LSM a small but essential component,
because it makes these features available without excessive
administrative burden. Many musicians have a Mac or Windows
background. They are not willing to perform complex system
administration tasks to get good audio performance. PAM is great for
sophisticated sysadmins on shared systems. But, I seriously doubt
many musicians will be able to configure it correctly. For a
single-user Digital Audio Workstation it is overkill.

So, even if you do provide a more general solution, I will probably
have to continue supporting the realtime-lsm interface throughout the
2.6 kernel life-cycle, as there will be enough users for it to be a
defacto standard. If it is no longer needed in the 2.8 timeframe, I
can drop support then.

It's hard to say how many people use realtime-lsm right now.
SourceForge lists about 1500 source downloads over the last six
months. Binary copies are included in the most popular audio-oriented
distributions, including Planet CCRMA and DeMuDi. I guess there are
probably no more than a few thousand active users."

Lee

2004-10-08 21:27:18

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Fri, 2004-10-08 at 17:21, Andrew Morton wrote:
> Lee Revell <[email protected]> wrote:
> >
> > Here's an updated patch, only
> > difference is line numbers.
>
> Nice patch. Wanna tell me something about what it's for?
>

Also, just to give a frame of reference, MacOS X (which is our real
competition in the pro audio area) just lets any user run RT tasks. So
this LSM would give us that needed functionality, but better, because
it's selective.

Lee

2004-10-08 21:46:16

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

* Lee Revell ([email protected]) wrote:
> + # sysctl -w security/realtime/any=0
> + # sysctl -w security/realtime/gid=29
> + # sysctl -w security/realtime/mlock=1
> +

I think these should move to sysfs.

> +Jack O'Quin, [email protected]
> diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/include/linux/sysctl.h linux-2.6.8.1-rt02/include/linux/sysctl.h
> --- linux-2.6.8.1/include/linux/sysctl.h Sat Aug 14 05:55:33 2004
> +++ linux-2.6.8.1-rt02/include/linux/sysctl.h Sun Oct 3 10:56:16 2004
> @@ -61,7 +61,14 @@
> CTL_DEV=7, /* Devices */
> CTL_BUS=8, /* Busses */
> CTL_ABI=9, /* Binary emulation */
> - CTL_CPU=10 /* CPU stuff (speed scaling, etc) */
> + CTL_CPU=10, /* CPU stuff (speed scaling, etc) */
> + CTL_SECURITY=11 /* Security modules */
> +};
> +
> +/* CTL_SECURITY names: */
> +enum
> +{
> + SECURITY_REALTIME=1 /* Realtime LSM */
> };

Without adding this extra bit.

> diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.8.1/security/Kconfig linux-2.6.8.1-rt02/security/Kconfig
> --- linux-2.6.8.1/security/Kconfig Sat Aug 14 05:55:47 2004
> +++ linux-2.6.8.1-rt02/security/Kconfig Sun Oct 3 10:56:17 2004
> @@ -84,6 +84,17 @@
>
> If you are unsure how to answer this question, answer N.
>
> +config SECURITY_REALTIME
> + tristate "Realtime Capabilities"
> + depends on SECURITY && SECURITY_CAPABILITIES!=y

Capabilities can be disabled on boot command line.

> --- linux-2.6.8.1/security/realtime.c Wed Dec 31 18:00:00 1969
> +++ linux-2.6.8.1-rt02/security/realtime.c Mon Oct 4 21:35:41 2004
> +static int any = 0; /* if TRUE, any process is realtime */

unecessary init to 0

> +MODULE_PARM(any, "i");

please use module_param (bonus, you get free entry on command line when
non-modular, and entry in /sysfs if you want).

> +MODULE_PARM_DESC(any, " grant realtime privileges to any process.");
> +
> +static int gid = -1; /* realtime group id, or NO_GROUP */
> +MODULE_PARM(gid, "i");

module_param.

> +MODULE_PARM_DESC(gid, " the group ID with access to realtime privileges.");
> +
> +static int mlock = 1; /* enable mlock() privileges */
> +MODULE_PARM(mlock, "i");

module_param.

> +MODULE_PARM_DESC(mlock, " enable memory locking privileges.");
> +
> +/* helper function for testing group membership */
> +static inline int gid_ok(int gid, int e_gid) {
> + int i;
> + int rt_ok = 0;
> +
> + if (gid == -1)
> + return 0;
> +
> + if ((gid == e_gid) || (gid == current->gid))
> + return 1;
> +
> + get_group_info(current->group_info);
> + for (i = 0; i < current->group_info->ngroups; ++i) {
> + if (gid == GROUP_AT(current->group_info, i)) {
> + rt_ok = 1;
> + break;
> + }
> + }

why not in_group_p?

> + put_group_info(current->group_info);
> +
> + return rt_ok;
> +}
> +
> +int realtime_bprm_set_security(struct linux_binprm *bprm)
> +{
> + /* Copied from security/commoncap.c: cap_bprm_set_security()... */
> + /* Copied from fs/exec.c:prepare_binprm. */
> + /* We don't have VFS support for capabilities yet */
> + cap_clear(bprm->cap_inheritable);
> + cap_clear(bprm->cap_permitted);
> + cap_clear(bprm->cap_effective);
> +
> + /* If a non-zero `any' parameter was specified, we grant
> + * realtime privileges to every process. If the `gid'
> + * parameter was specified and it matches the group id of the
> + * executable, of the current process or any supplementary
> + * groups, we grant realtime capabilites.
> + */
> +
> + if (any || gid_ok(gid, bprm->e_gid)) {
> + cap_raise(bprm->cap_effective, CAP_SYS_NICE);
> + cap_raise(bprm->cap_permitted, CAP_SYS_NICE);
> + if (mlock) {
> + cap_raise(bprm->cap_effective, CAP_IPC_LOCK);
> + cap_raise(bprm->cap_permitted, CAP_IPC_LOCK);
> + cap_raise(bprm->cap_effective,
> + CAP_SYS_RESOURCE);
> + cap_raise(bprm->cap_permitted,
> + CAP_SYS_RESOURCE);
> + }
> + }

Maybe it would be better to call cap_bprm_set_security first, then or in
the bits you care about. That way you don't have to worry about any changes
over there.

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-10-08 21:49:26

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Fri, 2004-10-08 at 17:45, Chris Wright wrote:
> > --- linux-2.6.8.1/security/realtime.c Wed Dec 31 18:00:00 1969
> > +++ linux-2.6.8.1-rt02/security/realtime.c Mon Oct 4 21:35:41 2004
> > +static int any = 0; /* if TRUE, any process is realtime */
>
> unecessary init to 0
>

I think gcc 3.4 complains otherwise.

Lee

2004-10-08 21:53:26

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

* Lee Revell ([email protected]) wrote:
> On Fri, 2004-10-08 at 17:45, Chris Wright wrote:
> > > --- linux-2.6.8.1/security/realtime.c Wed Dec 31 18:00:00 1969
> > > +++ linux-2.6.8.1-rt02/security/realtime.c Mon Oct 4 21:35:41 2004
> > > +static int any = 0; /* if TRUE, any process is realtime */
> >
> > unecessary init to 0
> >
>
> I think gcc 3.4 complains otherwise.

Nah, it's fine.

$ grep 'int any' security/realtime.c
static int any; /* if TRUE, any process is realtime */
$ make security/realtime.o
CC security/realtime.o
$ gcc --version
gcc (GCC) 3.4.2 20040907 (Red Hat 3.4.2-2)

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

--- security/realtime.c~orig 2004-10-08 14:27:27.000000000 -0700
+++ security/realtime.c 2004-10-08 14:52:31.303484080 -0700
@@ -26,6 +26,7 @@
#include <linux/netlink.h>
#include <linux/ptrace.h>
#include <linux/sysctl.h>
+#include <linux/moduleparam.h>

#ifdef CONFIG_SECURITY

@@ -46,16 +47,16 @@
* each is referenced only once in each function call. Nothing
* depends on parameters having the same value every time.
*/
-static int any = 0; /* if TRUE, any process is realtime */
-MODULE_PARM(any, "i");
+static int any; /* if TRUE, any process is realtime */
+module_param(any, int, 0644);
MODULE_PARM_DESC(any, " grant realtime privileges to any process.");

static int gid = -1; /* realtime group id, or NO_GROUP */
-MODULE_PARM(gid, "i");
+module_param(gid, int, 0644);
MODULE_PARM_DESC(gid, " the group ID with access to realtime privileges.");

static int mlock = 1; /* enable mlock() privileges */
-MODULE_PARM(mlock, "i");
+module_param(mlock, int, 0644);
MODULE_PARM_DESC(mlock, " enable memory locking privileges.");

/* helper function for testing group membership */

2004-10-08 22:07:42

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Fri, 2004-10-08 at 17:52, Chris Wright wrote:
> * Lee Revell ([email protected]) wrote:
> > On Fri, 2004-10-08 at 17:45, Chris Wright wrote:
> > > > --- linux-2.6.8.1/security/realtime.c Wed Dec 31 18:00:00 1969
> > > > +++ linux-2.6.8.1-rt02/security/realtime.c Mon Oct 4 21:35:41 2004
> > > > +static int any = 0; /* if TRUE, any process is realtime */
> > >
> > > unecessary init to 0
> > >
> >
> > I think gcc 3.4 complains otherwise.
>
> Nah, it's fine.
>
> $ grep 'int any' security/realtime.c
> static int any; /* if TRUE, any process is realtime */
> $ make security/realtime.o
> CC security/realtime.o
> $ gcc --version
> gcc (GCC) 3.4.2 20040907 (Red Hat 3.4.2-2)

So MODULE_PARM_DESC is neccesary even when using module_param instear of
MODULE_PARM?

Lee

2004-10-08 22:09:55

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

* Lee Revell ([email protected]) wrote:
> On Fri, 2004-10-08 at 17:52, Chris Wright wrote:
> > * Lee Revell ([email protected]) wrote:
> > > On Fri, 2004-10-08 at 17:45, Chris Wright wrote:
> > > > > --- linux-2.6.8.1/security/realtime.c Wed Dec 31 18:00:00 1969
> > > > > +++ linux-2.6.8.1-rt02/security/realtime.c Mon Oct 4 21:35:41 2004
> > > > > +static int any = 0; /* if TRUE, any process is realtime */
> > > >
> > > > unecessary init to 0
> > > >
> > >
> > > I think gcc 3.4 complains otherwise.
> >
> > Nah, it's fine.
> >
> > $ grep 'int any' security/realtime.c
> > static int any; /* if TRUE, any process is realtime */
> > $ make security/realtime.o
> > CC security/realtime.o
> > $ gcc --version
> > gcc (GCC) 3.4.2 20040907 (Red Hat 3.4.2-2)
>
> So MODULE_PARM_DESC is neccesary even when using module_param instear of
> MODULE_PARM?

YYeah, minor blemmish ;-)

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-10-08 22:19:33

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

relative to last one.

--- security/realtime.c~module_param 2004-10-08 15:03:41.000000000 -0700
+++ security/realtime.c 2004-10-08 15:18:40.627410864 -0700
@@ -84,12 +84,8 @@

int realtime_bprm_set_security(struct linux_binprm *bprm)
{
- /* Copied from security/commoncap.c: cap_bprm_set_security()... */
- /* Copied from fs/exec.c:prepare_binprm. */
- /* We don't have VFS support for capabilities yet */
- cap_clear(bprm->cap_inheritable);
- cap_clear(bprm->cap_permitted);
- cap_clear(bprm->cap_effective);
+
+ cap_bprm_set_security(bprm);

/* If a non-zero `any' parameter was specified, we grant
* realtime privileges to every process. If the `gid'
@@ -104,28 +100,10 @@
if (mlock) {
cap_raise(bprm->cap_effective, CAP_IPC_LOCK);
cap_raise(bprm->cap_permitted, CAP_IPC_LOCK);
- cap_raise(bprm->cap_effective,
- CAP_SYS_RESOURCE);
- cap_raise(bprm->cap_permitted,
- CAP_SYS_RESOURCE);
+ cap_raise(bprm->cap_effective, CAP_SYS_RESOURCE);
+ cap_raise(bprm->cap_permitted, CAP_SYS_RESOURCE);
}
}
-
- /* To support inheritance of root-permissions and suid-root
- * executables under compatibility mode, we raise all three
- * capability sets for the file.
- *
- * If only the real uid is 0, we only raise the inheritable
- * and permitted sets of the executable file.
- */
-
- if (bprm->e_uid == 0 || current->uid == 0) {
- cap_set_full(bprm->cap_inheritable);
- cap_set_full(bprm->cap_permitted);
- }
- if (bprm->e_uid == 0)
- cap_set_full(bprm->cap_effective);
-
return 0;
}

2004-10-08 22:24:48

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

(relative to last one)

use in_group_p

--- security/realtime.c~cap_bprm_set 2004-10-08 15:21:03.835639904 -0700
+++ security/realtime.c 2004-10-08 15:23:13.574916536 -0700
@@ -60,26 +60,15 @@
MODULE_PARM_DESC(mlock, " enable memory locking privileges.");

/* helper function for testing group membership */
-static inline int gid_ok(int gid, int e_gid) {
- int i;
- int rt_ok = 0;
-
+static inline int gid_ok(int gid, int e_gid)
+{
if (gid == -1)
return 0;

if ((gid == e_gid) || (gid == current->gid))
return 1;

- get_group_info(current->group_info);
- for (i = 0; i < current->group_info->ngroups; ++i) {
- if (gid == GROUP_AT(current->group_info, i)) {
- rt_ok = 1;
- break;
- }
- }
- put_group_info(current->group_info);
-
- return rt_ok;
+ return in_group_p(gid);
}

int realtime_bprm_set_security(struct linux_binprm *bprm)

2004-10-08 23:07:13

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Fri, 2004-10-08 at 18:24, Chris Wright wrote:
> (relative to last one)
>
> use in_group_p
>

Thanks! These make the patch even smaller and more comprehensible.
Does this cover all the issues with the patch as I posted it?

Lee

2004-10-08 23:12:29

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

* Lee Revell ([email protected]) wrote:
> On Fri, 2004-10-08 at 18:24, Chris Wright wrote:
> > (relative to last one)
> >
> > use in_group_p
> >
>
> Thanks! These make the patch even smaller and more comprehensible.
> Does this cover all the issues with the patch as I posted it?

The last bit is removing sysctls. It'll take a bit more effort, as we
need a touch of infrastructure for it. I'm working on that now. Here's
a couple really minor ones.

- make realtime_bprm_set_security static
- don't mark exit_security __exit, it's called from an __init function

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

--- security/realtime.c 2004-10-08 16:10:52.080357656 -0700
+++ security/realtime.c~in_group 2004-10-08 16:02:05.932344312 -0700
@@ -71,7 +71,7 @@
return in_group_p(gid);
}

-static int realtime_bprm_set_security(struct linux_binprm *bprm)
+int realtime_bprm_set_security(struct linux_binprm *bprm)
{

cap_bprm_set_security(bprm);
@@ -170,7 +170,7 @@

static int secondary; /* flag to keep track of how we were registered */

-static void exit_security(void)
+static void __exit exit_security(void)
{
/* remove ourselves from the security framework */
if (secondary) {

2004-10-08 23:20:57

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Fri, 2004-10-08 at 19:12, Chris Wright wrote:
> * Lee Revell ([email protected]) wrote:
> > On Fri, 2004-10-08 at 18:24, Chris Wright wrote:
> > > (relative to last one)
> > >
> > > use in_group_p
> > >
> >
> > Thanks! These make the patch even smaller and more comprehensible.
> > Does this cover all the issues with the patch as I posted it?
>
> The last bit is removing sysctls. It'll take a bit more effort, as we
> need a touch of infrastructure for it. I'm working on that now. Here's
> a couple really minor ones.
>
> - make realtime_bprm_set_security static
> - don't mark exit_security __exit, it's called from an __init function

I think the patch is reversed. It does the opposite of what you say in
both cases ;-). I fixed these by hand.

Thanks again.

Lee

2004-10-08 23:21:47

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

* Lee Revell ([email protected]) wrote:
> I think the patch is reversed. It does the opposite of what you say in
> both cases ;-). I fixed these by hand.

Ooops, thanks.

- rm unecessary #ifdef CONFIG_SECURITY

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net


--- security/realtime.c~static_exit 2004-10-08 16:12:14.199873592 -0700
+++ security/realtime.c 2004-10-08 16:15:43.915991896 -0700
@@ -28,8 +28,6 @@
#include <linux/sysctl.h>
#include <linux/moduleparam.h>

-#ifdef CONFIG_SECURITY
-
#define RT_LSM "Realtime LSM " /* syslog module name prefix */
#define RT_ERR "Realtime: " /* syslog error message prefix */

@@ -231,5 +229,3 @@

MODULE_DESCRIPTION("Realtime Capabilities Security Module");
MODULE_LICENSE("GPL");
-
-#endif /* CONFIG_SECURITY */

2004-10-09 01:01:52

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

Chris Wright <[email protected]> writes:

> use in_group_p

I looked at that, it wasn't clear to me whether to use in_group_p() or
in_egroup_p(). How do you choose?
--
joq

2004-10-09 05:16:43

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

* Jack O'Quin ([email protected]) wrote:
> Chris Wright <[email protected]> writes:
> > use in_group_p
>
> I looked at that, it wasn't clear to me whether to use in_group_p() or
> in_egroup_p(). How do you choose?

For most cases they'll be identical. The difference is whether you're
comparing the fsgid or the egid. The former is what's used for file
access, the latter might make more sense in your case. However, in
99.9% of the cases you care about fsgid == egid, so it's a wash. So,
in_egroup_p matches a bit better. Relative to the other patches...

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net


--- security/realtime.c~rm_CONFIG_SECURITY 2004-10-08 16:16:35.000000000 -0700
+++ security/realtime.c 2004-10-08 21:06:28.020084984 -0700
@@ -66,7 +66,7 @@
if ((gid == e_gid) || (gid == current->gid))
return 1;

- return in_group_p(gid);
+ return in_egroup_p(gid);
}

static int realtime_bprm_set_security(struct linux_binprm *bprm)

2004-10-09 16:17:12

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

Chris Wright <[email protected]> writes:

> * Jack O'Quin ([email protected]) wrote:
> > Chris Wright <[email protected]> writes:
> > > use in_group_p
> >
> > I looked at that, it wasn't clear to me whether to use in_group_p() or
> > in_egroup_p(). How do you choose?
>
> For most cases they'll be identical. The difference is whether you're
> comparing the fsgid or the egid. The former is what's used for file
> access, the latter might make more sense in your case. However, in
> 99.9% of the cases you care about fsgid == egid, so it's a wash. So,
> in_egroup_p matches a bit better. Relative to the other patches...

Thanks. I was familiar with gid, and egid from other Unix kernels,
but fsgid is new to me.

In what cases does it *differ* from the effective group ID?

> --- security/realtime.c~rm_CONFIG_SECURITY 2004-10-08 16:16:35.000000000 -0700
> +++ security/realtime.c 2004-10-08 21:06:28.020084984 -0700
> @@ -66,7 +66,7 @@
> if ((gid == e_gid) || (gid == current->gid))
> return 1;
>
> - return in_group_p(gid);
> + return in_egroup_p(gid);
> }
>
> static int realtime_bprm_set_security(struct linux_binprm *bprm)

This adds a test against current->egid in addition to the explicit
check of current->gid. I don't see any problem with that. AFAICT,
the current->gid check is still useful.
--
joq

2004-10-09 19:11:48

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

* Jack O'Quin ([email protected]) wrote:
> Thanks. I was familiar with gid, and egid from other Unix kernels,
> but fsgid is new to me.
>
> In what cases does it *differ* from the effective group ID?

If the program calls setfsgid. It would typically only do this if it
wanted to assume a new gid for filesystem access on behalf of someone
else (e.g. file server).

> > --- security/realtime.c~rm_CONFIG_SECURITY 2004-10-08 16:16:35.000000000 -0700
> > +++ security/realtime.c 2004-10-08 21:06:28.020084984 -0700
> > @@ -66,7 +66,7 @@
> > if ((gid == e_gid) || (gid == current->gid))
> > return 1;
> >
> > - return in_group_p(gid);
> > + return in_egroup_p(gid);
> > }
> >
> > static int realtime_bprm_set_security(struct linux_binprm *bprm)
>
> This adds a test against current->egid in addition to the explicit
> check of current->gid. I don't see any problem with that. AFAICT,
> the current->gid check is still useful.

The egid makes a setgid-audio program be meaningful as well.

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-10-09 20:30:43

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

> * Jack O'Quin ([email protected]) wrote:
> > This adds a test against current->egid in addition to the explicit
> > check of current->gid. I don't see any problem with that. AFAICT,
> > the current->gid check is still useful.

Chris Wright <[email protected]> writes:
> The egid makes a setgid-audio program be meaningful as well.

That works already, because we test the e_gid from the bprm structure,
right? Is that redundant?
--
joq

2004-10-09 22:53:59

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

* Jack O'Quin ([email protected]) wrote:
> Chris Wright <[email protected]> writes:
> > The egid makes a setgid-audio program be meaningful as well.
>
> That works already, because we test the e_gid from the bprm structure,
> right? Is that redundant?

You're right. It's not quite redundant, because current->egid test is
before current->egid would be reset on setgid (happens in apply_creds).
Using apply_creds actually makes a bit more sense here, and simplifies
things a touch.

- use apply_creds and update gid_ok accordingly
- only upgrade cap_effective
- less generic variable names
- s/any/rt_any/
- s/gid/rt_gid/
- s/mlock/rt_mlock/

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

--- security/realtime.c~in_egroup 2004-10-08 22:17:23.499153832 -0700
+++ security/realtime.c 2004-10-09 15:49:38.048243488 -0700
@@ -45,34 +45,37 @@
* each is referenced only once in each function call. Nothing
* depends on parameters having the same value every time.
*/
-static int any; /* if TRUE, any process is realtime */
-module_param(any, int, 0644);
+
+/* if TRUE, any process is realtime */
+static int rt_any;
+module_param_named(any, rt_any, int, 0644);
MODULE_PARM_DESC(any, " grant realtime privileges to any process.");

-static int gid = -1; /* realtime group id, or NO_GROUP */
-module_param(gid, int, 0644);
+/* realtime group id, or NO_GROUP */
+static int rt_gid = -1;
+module_param_named(gid, rt_gid, int, 0644);
MODULE_PARM_DESC(gid, " the group ID with access to realtime privileges.");

-static int mlock = 1; /* enable mlock() privileges */
-module_param(mlock, int, 0644);
+/* enable mlock() privileges */
+static int rt_mlock = 1;
+module_param_named(mlock, rt_mlock, int, 0644);
MODULE_PARM_DESC(mlock, " enable memory locking privileges.");

/* helper function for testing group membership */
-static inline int gid_ok(int gid, int e_gid)
+static inline int gid_ok(int gid)
{
if (gid == -1)
return 0;

- if ((gid == e_gid) || (gid == current->gid))
+ if (gid == current->gid)
return 1;

return in_egroup_p(gid);
}

-static int realtime_bprm_set_security(struct linux_binprm *bprm)
+static void realtime_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
{
-
- cap_bprm_set_security(bprm);
+ cap_bprm_apply_creds(bprm, unsafe);

/* If a non-zero `any' parameter was specified, we grant
* realtime privileges to every process. If the `gid'
@@ -81,17 +84,13 @@
* groups, we grant realtime capabilites.
*/

- if (any || gid_ok(gid, bprm->e_gid)) {
- cap_raise(bprm->cap_effective, CAP_SYS_NICE);
- cap_raise(bprm->cap_permitted, CAP_SYS_NICE);
- if (mlock) {
- cap_raise(bprm->cap_effective, CAP_IPC_LOCK);
- cap_raise(bprm->cap_permitted, CAP_IPC_LOCK);
- cap_raise(bprm->cap_effective, CAP_SYS_RESOURCE);
- cap_raise(bprm->cap_permitted, CAP_SYS_RESOURCE);
+ if (rt_any || gid_ok(rt_gid)) {
+ cap_raise(current->cap_effective, CAP_SYS_NICE);
+ if (rt_mlock) {
+ cap_raise(current->cap_effective, CAP_IPC_LOCK);
+ cap_raise(current->cap_effective, CAP_SYS_RESOURCE);
}
}
- return 0;
}

static struct security_operations capability_ops = {
@@ -102,8 +101,8 @@
.capable = cap_capable,
.netlink_send = cap_netlink_send,
.netlink_recv = cap_netlink_recv,
- .bprm_apply_creds = cap_bprm_apply_creds,
- .bprm_set_security = realtime_bprm_set_security,
+ .bprm_apply_creds = realtime_bprm_apply_creds,
+ .bprm_set_security = cap_bprm_set_security,
.bprm_secureexec = cap_bprm_secureexec,
.task_post_setuid = cap_task_post_setuid,
.task_reparent_to_init = cap_task_reparent_to_init,
@@ -117,14 +116,14 @@
{
{ .ctl_name = 1,
.procname = "any",
- .data = &any,
+ .data = &rt_any,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
},
{ .ctl_name = 2,
.procname = "gid",
- .data = &gid,
+ .data = &rt_gid,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
@@ -133,7 +132,7 @@
},
{ .ctl_name = 3,
.procname = "mlock",
- .data = &mlock,
+ .data = &rt_mlock,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
@@ -205,15 +204,15 @@
return -ENOMEM;
}

- if (any)
+ if (rt_any)
printk(KERN_INFO RT_LSM
- "initialized (all groups, mlock=%d)\n", mlock);
- else if (gid == -1)
+ "initialized (all groups, mlock=%d)\n", rt_mlock);
+ else if (rt_gid == -1)
printk(KERN_INFO RT_LSM
- "initialized (no groups, mlock=%d)\n", mlock);
+ "initialized (no groups, mlock=%d)\n", rt_mlock);
else
printk(KERN_INFO RT_LSM
- "initialized (group %d, mlock=%d)\n", gid, mlock);
+ "initialized (group %d, mlock=%d)\n", rt_gid, rt_mlock);

return 0;
}

2004-10-15 01:55:26

by Rusty Russell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Fri, 2004-10-01 at 07:14, Jody McIntyre wrote:
> +/* module parameters */
> +static int any = 0; /* if TRUE, any process is realtime */
> +MODULE_PARM(any, "i");

Please node that MODULE_PARM is deprecated. This looks like a job for
"module_param(any, bool, 0400)" or even "0644". Please consider, and
for the others.

Thanks,
Rusty.
--
Anyone who quotes me in their signature is an idiot -- Rusty Russell

2004-10-15 02:15:50

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Thu, 2004-10-14 at 21:55, Rusty Russell wrote:
> On Fri, 2004-10-01 at 07:14, Jody McIntyre wrote:
> > +/* module parameters */
> > +static int any = 0; /* if TRUE, any process is realtime */
> > +MODULE_PARM(any, "i");
>
> Please node that MODULE_PARM is deprecated. This looks like a job for
> "module_param(any, bool, 0400)" or even "0644". Please consider, and
> for the others.

This change (along with many other improvements) was already made by
Chris Wright. An updated patch will probably be posted soon.

Lee

2004-10-23 00:08:47

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

Chris Wright <[email protected]> writes:

> - less generic variable names
> - s/any/rt_any/
> - s/gid/rt_gid/
> - s/mlock/rt_mlock/

Is there a compelling reason for changing all the parameter names?

I would prefer not to do that. It is incompatible for our current
user base, and really does not seem like an improvement. Those names
only appear in the context of `realtime', so the `rt_' is completely
redundant. For example...

# modprobe realtime gid=29
# sysctl -w security/realtime/mlock=0

Also, you forgot to update the documentation.
--
joq

2004-10-23 00:41:35

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Fri, 2004-10-22 at 18:59 -0500, Jack O'Quin wrote:
> Chris Wright <[email protected]> writes:
>
> > - less generic variable names
> > - s/any/rt_any/
> > - s/gid/rt_gid/
> > - s/mlock/rt_mlock/
>
> Is there a compelling reason for changing all the parameter names?
>
> I would prefer not to do that. It is incompatible for our current
> user base, and really does not seem like an improvement. Those names
> only appear in the context of `realtime', so the `rt_' is completely
> redundant. For example...

I think the reason was to make the code more readable. How about just
mapping the parameters to internal names by prepending rt_?

Lee

2004-10-23 01:28:14

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

> Chris Wright <[email protected]> writes:
>
> > - less generic variable names
> > - s/any/rt_any/
> > - s/gid/rt_gid/
> > - s/mlock/rt_mlock/

Jack O'Quin <[email protected]> writes:
> Is there a compelling reason for changing all the parameter names?
>
> I would prefer not to do that. It is incompatible for our current
> user base, and really does not seem like an improvement. Those names
> only appear in the context of `realtime', so the `rt_' is completely
> redundant.

Studying his code, I see that I misunderstood what Chris had done.

Only the internal static variable names changed. There is no change
to the user interface.

I have no objection at all to that, it's a good idea.
--
joq

2004-10-23 01:32:27

by Lee Revell

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

On Fri, 2004-10-22 at 20:23 -0500, Jack O'Quin wrote:
> > Chris Wright <[email protected]> writes:
> >
> > > - less generic variable names
> > > - s/any/rt_any/
> > > - s/gid/rt_gid/
> > > - s/mlock/rt_mlock/

OK for those of you not playing along at home, here is the latest
version of the realtime LSM with all Chris' fixes, as a patch against
2.6.9-mm1.

http://krustophenia.net/realtime-lsm-2.6.9-mm1.patch

I think the only change still needed is to remove the sysctl stuff.

--
Lee Revell <[email protected]>

2004-10-23 05:15:16

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

Lee Revell <[email protected]> writes:

> OK for those of you not playing along at home, here is the latest
> version of the realtime LSM with all Chris' fixes, as a patch against
> 2.6.9-mm1.
>
> http://krustophenia.net/realtime-lsm-2.6.9-mm1.patch
>
> I think the only change still needed is to remove the sysctl stuff.

Your diff picked up a bogus patch in `security/Kconfig.orig', mostly
harmless, AFAICT, but it should be removed. The Makefile patch was
missing, so realtime.c doesn't get compiled.

These minor corrections are included in the version appended below.
I'll give it some testing tomorrow, let you know if I find a problem.
--
joq

diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.9/Documentation/realtime-lsm.txt linux-2.6.9-rt1/Documentation/realtime-lsm.txt
--- linux-2.6.9/Documentation/realtime-lsm.txt Wed Dec 31 18:00:00 1969
+++ linux-2.6.9-rt1/Documentation/realtime-lsm.txt Fri Oct 22 23:26:21 2004
@@ -0,0 +1,38 @@
+
+ Realtime Linux Security Module
+
+
+This Linux Security Module (LSM) enables realtime capabilities. It
+was written by Torben Hohn and Jack O'Quin, under the provisions of
+the GPL (see the COPYING file). We make no warranty concerning the
+safety, security or even stability of your system when using it. But,
+we will fix problems if you report them.
+
+Once the LSM has been installed and the kernel for which it was built
+is running, the root user can load it and pass parameters as follows:
+
+ # modprobe realtime any=1
+
+ Any program can request realtime privileges. This allows any local
+ user to crash the system by hogging the CPU in a tight loop or
+ locking down too much memory. But, it is simple to administer. :-)
+
+ # modprobe realtime gid=29
+
+ All users belonging to group 29 and programs that are setgid to that
+ group have realtime privileges. Use any group number you like. A
+ `gid' of -1 disables group access.
+
+ # modprobe realtime mlock=0
+
+ Grants realtime scheduling privileges without the ability to lock
+ memory using mlock() or mlockall() system calls. This option can be
+ used in conjunction with any of the other options.
+
+Parameters can be changed dynamically via /proc/sys/security/realtime:
+
+ # sysctl -w security/realtime/any=0
+ # sysctl -w security/realtime/gid=29
+ # sysctl -w security/realtime/mlock=1
+
+Jack O'Quin, [email protected]
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.9/include/linux/sysctl.h linux-2.6.9-rt1/include/linux/sysctl.h
--- linux-2.6.9/include/linux/sysctl.h Mon Oct 18 16:54:31 2004
+++ linux-2.6.9-rt1/include/linux/sysctl.h Fri Oct 22 23:27:21 2004
@@ -61,7 +61,14 @@
CTL_DEV=7, /* Devices */
CTL_BUS=8, /* Busses */
CTL_ABI=9, /* Binary emulation */
- CTL_CPU=10 /* CPU stuff (speed scaling, etc) */
+ CTL_CPU=10, /* CPU stuff (speed scaling, etc) */
+ CTL_SECURITY=11 /* Security modules */
+};
+
+/* CTL_SECURITY names: */
+enum
+{
+ SECURITY_REALTIME=1 /* Realtime LSM */
};

/* CTL_BUS names: */
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.9/security/Kconfig linux-2.6.9-rt1/security/Kconfig
--- linux-2.6.9/security/Kconfig Mon Oct 18 16:54:39 2004
+++ linux-2.6.9-rt1/security/Kconfig Fri Oct 22 23:26:22 2004
@@ -44,6 +44,17 @@

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

+config SECURITY_REALTIME
+ tristate "Realtime Capabilities"
+ depends on SECURITY && SECURITY_CAPABILITIES!=y
+ default n
+ help
+ This module selectively grants realtime privileges
+ controlled by load-time parameters and
+ /proc/sys/security/realtime.
+
+ If you are unsure how to answer this question, answer N.
+
source security/selinux/Kconfig

endmenu
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.9/security/Makefile linux-2.6.9-rt1/security/Makefile
--- linux-2.6.9/security/Makefile Mon Oct 18 16:54:39 2004
+++ linux-2.6.9-rt1/security/Makefile Fri Oct 22 23:59:30 2004
@@ -15,3 +15,4 @@
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_REALTIME) += commoncap.o realtime.o
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.9/security/realtime.c linux-2.6.9-rt1/security/realtime.c
--- linux-2.6.9/security/realtime.c Wed Dec 31 18:00:00 1969
+++ linux-2.6.9-rt1/security/realtime.c Fri Oct 22 23:27:21 2004
@@ -0,0 +1,230 @@
+/*
+ * Realtime Capabilities Linux Security Module
+ *
+ * Copyright (C) 2003 Torben Hohn
+ * Copyright (C) 2003, 2004 Jack O'Quin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/ptrace.h>
+#include <linux/sysctl.h>
+#include <linux/moduleparam.h>
+
+#define RT_LSM "Realtime LSM " /* syslog module name prefix */
+#define RT_ERR "Realtime: " /* syslog error message prefix */
+
+#include <linux/vermagic.h>
+MODULE_INFO(vermagic,VERMAGIC_STRING);
+
+/* this is needed for the proc_dointvec_minmax for allowed GID */
+static int maxuid = 65535;
+static int minuid = -1;
+
+/* module parameters
+ *
+ * These values could change at any time due to some process writing
+ * a new value to /proc/sys/security/realtime. This is OK, because
+ * each is referenced only once in each function call. Nothing
+ * depends on parameters having the same value every time.
+ */
+
+/* if TRUE, any process is realtime */
+static int rt_any;
+module_param_named(any, rt_any, int, 0644);
+MODULE_PARM_DESC(any, " grant realtime privileges to any process.");
+
+/* realtime group id, or NO_GROUP */
+static int rt_gid = -1;
+module_param_named(gid, rt_gid, int, 0644);
+MODULE_PARM_DESC(gid, " the group ID with access to realtime privileges.");
+
+/* enable mlock() privileges */
+static int rt_mlock = 1;
+module_param_named(mlock, rt_mlock, int, 0644);
+MODULE_PARM_DESC(mlock, " enable memory locking privileges.");
+
+/* helper function for testing group membership */
+static inline int gid_ok(int gid)
+{
+ if (gid == -1)
+ return 0;
+
+ if (gid == current->gid)
+ return 1;
+
+ return in_egroup_p(gid);
+}
+
+static void realtime_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
+{
+ cap_bprm_apply_creds(bprm, unsafe);
+
+ /* If a non-zero `any' parameter was specified, we grant
+ * realtime privileges to every process. If the `gid'
+ * parameter was specified and it matches the group id of the
+ * executable, of the current process or any supplementary
+ * groups, we grant realtime capabilites.
+ */
+
+ if (rt_any || gid_ok(rt_gid)) {
+ cap_raise(current->cap_effective, CAP_SYS_NICE);
+ if (rt_mlock) {
+ cap_raise(current->cap_effective, CAP_IPC_LOCK);
+ cap_raise(current->cap_effective, CAP_SYS_RESOURCE);
+ }
+ }
+}
+
+static struct security_operations capability_ops = {
+ .ptrace = cap_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+ .bprm_apply_creds = realtime_bprm_apply_creds,
+ .bprm_set_security = cap_bprm_set_security,
+ .bprm_secureexec = cap_bprm_secureexec,
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+ .syslog = cap_syslog,
+ .vm_enough_memory = cap_vm_enough_memory,
+};
+
+#define MY_NAME __stringify(KBUILD_MODNAME)
+
+static ctl_table realtime_table[] =
+{
+ { .ctl_name = 1,
+ .procname = "any",
+ .data = &rt_any,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { .ctl_name = 2,
+ .procname = "gid",
+ .data = &rt_gid,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = &minuid,
+ .extra2 = &maxuid
+ },
+ { .ctl_name = 3,
+ .procname = "mlock",
+ .data = &rt_mlock,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { }
+};
+
+static ctl_table realtime_root_table[] =
+{
+ { .ctl_name = SECURITY_REALTIME,
+ .procname = "realtime",
+ .mode = 0555,
+ .child = realtime_table },
+ { }
+};
+
+static ctl_table security_root_table[] =
+{
+ { .ctl_name = CTL_SECURITY,
+ .procname = "security",
+ .mode = 0555,
+ .child = realtime_root_table },
+ { }
+};
+
+static struct ctl_table_header *sysctl_header;
+
+static void __exit exit_sysctl(void)
+{
+ unregister_sysctl_table(sysctl_header);
+}
+
+static int secondary; /* flag to keep track of how we were registered */
+
+static void exit_security(void)
+{
+ /* remove ourselves from the security framework */
+ if (secondary) {
+ if (mod_unreg_security(MY_NAME, &capability_ops))
+ printk(KERN_INFO RT_ERR "Failure unregistering "
+ "capabilities with primary module.\n");
+
+ } else if (unregister_security(&capability_ops)) {
+ printk(KERN_INFO RT_ERR
+ "Failure unregistering capabilities with the kernel\n");
+ }
+ printk(KERN_INFO "Realtime Capability LSM exiting\n");
+}
+
+static int __init capability_init(void)
+{
+ /* register ourselves with the security framework */
+ if (register_security(&capability_ops)) {
+
+ /* try registering with primary module */
+ if (mod_reg_security(MY_NAME, &capability_ops)) {
+ printk(KERN_INFO RT_ERR "Failure registering "
+ "capabilities with primary security module.\n");
+ printk(KERN_INFO RT_ERR "Is kernel configured "
+ "with CONFIG_SECURITY_CAPABILITIES=m?\n");
+ return -EINVAL;
+ }
+ secondary = 1;
+ }
+
+ sysctl_header = register_sysctl_table(security_root_table, 0);
+ if (!sysctl_header) {
+ exit_security();
+ return -ENOMEM;
+ }
+
+ if (rt_any)
+ printk(KERN_INFO RT_LSM
+ "initialized (all groups, mlock=%d)\n", rt_mlock);
+ else if (rt_gid == -1)
+ printk(KERN_INFO RT_LSM
+ "initialized (no groups, mlock=%d)\n", rt_mlock);
+ else
+ printk(KERN_INFO RT_LSM
+ "initialized (group %d, mlock=%d)\n", rt_gid, rt_mlock);
+
+ return 0;
+}
+
+static void __exit capability_exit(void)
+{
+ exit_sysctl();
+ exit_security();
+}
+
+late_initcall(capability_init);
+module_exit(capability_exit);
+
+MODULE_DESCRIPTION("Realtime Capabilities Security Module");
+MODULE_LICENSE("GPL");

2004-10-23 18:17:51

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

Jack O'Quin <[email protected]> writes:

> These minor corrections are included in the version appended below.
> I'll give it some testing tomorrow, let you know if I find a problem.

AFAICT it works with 2.6.9, but the realtime performance is terrible
(2.6.8.1 was much better). The appropriate threads are running
SCHED_FIFO, but there are frequent xruns. Could some change in the
kernel be affecting this?

I'm going to to try 2.6.9-mm1, to see if that works better.
--
joq

2004-10-23 20:07:34

by Chris Wright

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

* Jack O'Quin ([email protected]) wrote:
> Chris Wright <[email protected]> writes:
>
> > - less generic variable names
> > - s/any/rt_any/
> > - s/gid/rt_gid/
> > - s/mlock/rt_mlock/
>
> Is there a compelling reason for changing all the parameter names?

primarly for namespace cleanliness. nice to avoid overly generic names
if possible. makes it easier to search.

> I would prefer not to do that. It is incompatible for our current
> user base, and really does not seem like an improvement. Those names
> only appear in the context of `realtime', so the `rt_' is completely
> redundant. For example...

Actually, I recall the change being 100% internal (not exposed
externally), but I'm away at the moment, so it's just from memory.

> # modprobe realtime gid=29
> # sysctl -w security/realtime/mlock=0
>
> Also, you forgot to update the documentation.

I don't think it was needed due to above.

thanks,
-chris
--
Linux Security Modules http://lsm.immunix.org http://lsm.bkbits.net

2004-10-25 02:04:36

by Jack O'Quin

[permalink] [raw]
Subject: Re: [PATCH] Realtime LSM

Jack O'Quin <[email protected]> writes:

> AFAICT it works with 2.6.9, but the realtime performance is terrible
> (2.6.8.1 was much better). The appropriate threads are running
> SCHED_FIFO, but there are frequent xruns. Could some change in the
> kernel be affecting this?
>
> I'm going to to try 2.6.9-mm1, to see if that works better.

2.6.9-mm1 works fine. I'm appending an updated complete version of
the patch for that kernel (the 2.6.9 patch did not apply cleanly).

As Lee already stated, this version is not final, because it still
exposes its parameters to sysctl via /proc/sys/security/realtime.

Chris Wright prefers to do that differently, using sysfs. I defer to
his judgement about that, but don't understand what he has in mind
well enough to actually implement it myself. Clearly, this LSM should
handle parameters however the others do or will.
--
joq

diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.9-mm1/Documentation/realtime-lsm.txt linux-2.6.9-mm1-rt1/Documentation/realtime-lsm.txt
--- linux-2.6.9-mm1/Documentation/realtime-lsm.txt Wed Dec 31 18:00:00 1969
+++ linux-2.6.9-mm1-rt1/Documentation/realtime-lsm.txt Sun Oct 24 13:29:22 2004
@@ -0,0 +1,38 @@
+
+ Realtime Linux Security Module
+
+
+This Linux Security Module (LSM) enables realtime capabilities. It
+was written by Torben Hohn and Jack O'Quin, under the provisions of
+the GPL (see the COPYING file). We make no warranty concerning the
+safety, security or even stability of your system when using it. But,
+we will fix problems if you report them.
+
+Once the LSM has been installed and the kernel for which it was built
+is running, the root user can load it and pass parameters as follows:
+
+ # modprobe realtime any=1
+
+ Any program can request realtime privileges. This allows any local
+ user to crash the system by hogging the CPU in a tight loop or
+ locking down too much memory. But, it is simple to administer. :-)
+
+ # modprobe realtime gid=29
+
+ All users belonging to group 29 and programs that are setgid to that
+ group have realtime privileges. Use any group number you like. A
+ `gid' of -1 disables group access.
+
+ # modprobe realtime mlock=0
+
+ Grants realtime scheduling privileges without the ability to lock
+ memory using mlock() or mlockall() system calls. This option can be
+ used in conjunction with any of the other options.
+
+Parameters can be changed dynamically via /proc/sys/security/realtime:
+
+ # sysctl -w security/realtime/any=0
+ # sysctl -w security/realtime/gid=29
+ # sysctl -w security/realtime/mlock=1
+
+Jack O'Quin, [email protected]
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.9-mm1/include/linux/sysctl.h linux-2.6.9-mm1-rt1/include/linux/sysctl.h
--- linux-2.6.9-mm1/include/linux/sysctl.h Sun Oct 24 13:14:59 2004
+++ linux-2.6.9-mm1-rt1/include/linux/sysctl.h Sun Oct 24 13:29:22 2004
@@ -61,7 +61,14 @@
CTL_DEV=7, /* Devices */
CTL_BUS=8, /* Busses */
CTL_ABI=9, /* Binary emulation */
- CTL_CPU=10 /* CPU stuff (speed scaling, etc) */
+ CTL_CPU=10, /* CPU stuff (speed scaling, etc) */
+ CTL_SECURITY=11 /* Security modules */
+};
+
+/* CTL_SECURITY names: */
+enum
+{
+ SECURITY_REALTIME=1 /* Realtime LSM */
};

/* CTL_BUS names: */
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.9-mm1/security/Kconfig linux-2.6.9-mm1-rt1/security/Kconfig
--- linux-2.6.9-mm1/security/Kconfig Sun Oct 24 13:15:02 2004
+++ linux-2.6.9-mm1-rt1/security/Kconfig Sun Oct 24 13:29:22 2004
@@ -84,6 +84,17 @@

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

+config SECURITY_REALTIME
+ tristate "Realtime Capabilities"
+ depends on SECURITY && SECURITY_CAPABILITIES!=y
+ default n
+ help
+ This module selectively grants realtime privileges
+ controlled by load-time parameters and
+ /proc/sys/security/realtime.
+
+ If you are unsure how to answer this question, answer N.
+
source security/selinux/Kconfig

endmenu
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.9-mm1/security/Makefile linux-2.6.9-mm1-rt1/security/Makefile
--- linux-2.6.9-mm1/security/Makefile Sun Oct 24 13:15:02 2004
+++ linux-2.6.9-mm1-rt1/security/Makefile Sun Oct 24 13:30:08 2004
@@ -17,3 +17,4 @@
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
obj-$(CONFIG_SECURITY_SECLVL) += seclvl.o
+obj-$(CONFIG_SECURITY_REALTIME) += commoncap.o realtime.o
diff -ruN -X /home/joq/bin/kdiff.exclude linux-2.6.9-mm1/security/realtime.c linux-2.6.9-mm1-rt1/security/realtime.c
--- linux-2.6.9-mm1/security/realtime.c Wed Dec 31 18:00:00 1969
+++ linux-2.6.9-mm1-rt1/security/realtime.c Sun Oct 24 13:29:22 2004
@@ -0,0 +1,230 @@
+/*
+ * Realtime Capabilities Linux Security Module
+ *
+ * Copyright (C) 2003 Torben Hohn
+ * Copyright (C) 2003, 2004 Jack O'Quin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/ptrace.h>
+#include <linux/sysctl.h>
+#include <linux/moduleparam.h>
+
+#define RT_LSM "Realtime LSM " /* syslog module name prefix */
+#define RT_ERR "Realtime: " /* syslog error message prefix */
+
+#include <linux/vermagic.h>
+MODULE_INFO(vermagic,VERMAGIC_STRING);
+
+/* this is needed for the proc_dointvec_minmax for allowed GID */
+static int maxuid = 65535;
+static int minuid = -1;
+
+/* module parameters
+ *
+ * These values could change at any time due to some process writing
+ * a new value to /proc/sys/security/realtime. This is OK, because
+ * each is referenced only once in each function call. Nothing
+ * depends on parameters having the same value every time.
+ */
+
+/* if TRUE, any process is realtime */
+static int rt_any;
+module_param_named(any, rt_any, int, 0644);
+MODULE_PARM_DESC(any, " grant realtime privileges to any process.");
+
+/* realtime group id, or NO_GROUP */
+static int rt_gid = -1;
+module_param_named(gid, rt_gid, int, 0644);
+MODULE_PARM_DESC(gid, " the group ID with access to realtime privileges.");
+
+/* enable mlock() privileges */
+static int rt_mlock = 1;
+module_param_named(mlock, rt_mlock, int, 0644);
+MODULE_PARM_DESC(mlock, " enable memory locking privileges.");
+
+/* helper function for testing group membership */
+static inline int gid_ok(int gid)
+{
+ if (gid == -1)
+ return 0;
+
+ if (gid == current->gid)
+ return 1;
+
+ return in_egroup_p(gid);
+}
+
+static void realtime_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
+{
+ cap_bprm_apply_creds(bprm, unsafe);
+
+ /* If a non-zero `any' parameter was specified, we grant
+ * realtime privileges to every process. If the `gid'
+ * parameter was specified and it matches the group id of the
+ * executable, of the current process or any supplementary
+ * groups, we grant realtime capabilites.
+ */
+
+ if (rt_any || gid_ok(rt_gid)) {
+ cap_raise(current->cap_effective, CAP_SYS_NICE);
+ if (rt_mlock) {
+ cap_raise(current->cap_effective, CAP_IPC_LOCK);
+ cap_raise(current->cap_effective, CAP_SYS_RESOURCE);
+ }
+ }
+}
+
+static struct security_operations capability_ops = {
+ .ptrace = cap_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+ .bprm_apply_creds = realtime_bprm_apply_creds,
+ .bprm_set_security = cap_bprm_set_security,
+ .bprm_secureexec = cap_bprm_secureexec,
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+ .syslog = cap_syslog,
+ .vm_enough_memory = cap_vm_enough_memory,
+};
+
+#define MY_NAME __stringify(KBUILD_MODNAME)
+
+static ctl_table realtime_table[] =
+{
+ { .ctl_name = 1,
+ .procname = "any",
+ .data = &rt_any,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { .ctl_name = 2,
+ .procname = "gid",
+ .data = &rt_gid,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .extra1 = &minuid,
+ .extra2 = &maxuid
+ },
+ { .ctl_name = 3,
+ .procname = "mlock",
+ .data = &rt_mlock,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { }
+};
+
+static ctl_table realtime_root_table[] =
+{
+ { .ctl_name = SECURITY_REALTIME,
+ .procname = "realtime",
+ .mode = 0555,
+ .child = realtime_table },
+ { }
+};
+
+static ctl_table security_root_table[] =
+{
+ { .ctl_name = CTL_SECURITY,
+ .procname = "security",
+ .mode = 0555,
+ .child = realtime_root_table },
+ { }
+};
+
+static struct ctl_table_header *sysctl_header;
+
+static void __exit exit_sysctl(void)
+{
+ unregister_sysctl_table(sysctl_header);
+}
+
+static int secondary; /* flag to keep track of how we were registered */
+
+static void exit_security(void)
+{
+ /* remove ourselves from the security framework */
+ if (secondary) {
+ if (mod_unreg_security(MY_NAME, &capability_ops))
+ printk(KERN_INFO RT_ERR "Failure unregistering "
+ "capabilities with primary module.\n");
+
+ } else if (unregister_security(&capability_ops)) {
+ printk(KERN_INFO RT_ERR
+ "Failure unregistering capabilities with the kernel\n");
+ }
+ printk(KERN_INFO "Realtime Capability LSM exiting\n");
+}
+
+static int __init capability_init(void)
+{
+ /* register ourselves with the security framework */
+ if (register_security(&capability_ops)) {
+
+ /* try registering with primary module */
+ if (mod_reg_security(MY_NAME, &capability_ops)) {
+ printk(KERN_INFO RT_ERR "Failure registering "
+ "capabilities with primary security module.\n");
+ printk(KERN_INFO RT_ERR "Is kernel configured "
+ "with CONFIG_SECURITY_CAPABILITIES=m?\n");
+ return -EINVAL;
+ }
+ secondary = 1;
+ }
+
+ sysctl_header = register_sysctl_table(security_root_table, 0);
+ if (!sysctl_header) {
+ exit_security();
+ return -ENOMEM;
+ }
+
+ if (rt_any)
+ printk(KERN_INFO RT_LSM
+ "initialized (all groups, mlock=%d)\n", rt_mlock);
+ else if (rt_gid == -1)
+ printk(KERN_INFO RT_LSM
+ "initialized (no groups, mlock=%d)\n", rt_mlock);
+ else
+ printk(KERN_INFO RT_LSM
+ "initialized (group %d, mlock=%d)\n", rt_gid, rt_mlock);
+
+ return 0;
+}
+
+static void __exit capability_exit(void)
+{
+ exit_sysctl();
+ exit_security();
+}
+
+late_initcall(capability_init);
+module_exit(capability_exit);
+
+MODULE_DESCRIPTION("Realtime Capabilities Security Module");
+MODULE_LICENSE("GPL");