| From: |
| Michael Halcrow <mike@halcrow.us> |
| To: |
| linux-security-module@wirex.com |
| Subject: |
| [PATCH] settime hooks (1/1) |
| Date: |
| Thu, 5 Aug 2004 15:13:59 -0500 |
For final review before sending them off to LKML. Please let me know
if anything looks amiss. This is in support of the BSD Secure Levels
LSM that follow.
Mike
.___________________________________________________________________.
Michael A. Halcrow
Security Software Engineer, IBM Linux Technology Center
GnuPG Fingerprint: 05B5 08A8 713A 64C1 D35D 2371 2D3C FDDA 3EB6 601D
--- linux-2.6.7/arch/mips/kernel/sysirix.c 2004-06-16 00:20:03.000000000 -0500
+++ linux-2.6.7_seclvl/arch/mips/kernel/sysirix.c 2004-08-05 10:32:11.000000000 -0500
@@ -614,8 +614,15 @@
asmlinkage int irix_stime(int value)
{
- if (!capable(CAP_SYS_TIME))
- return -EPERM;
+ int err;
+ struct timespec tv;
+
+ /* Call the Linux Security Module to perform its checks */
+ tv.tv_sec = value;
+ tv.tv_nsec = 0;
+ err = security_settime(&tv, NULL);
+ if (err)
+ return err;
write_seqlock_irq(&xtime_lock);
xtime.tv_sec = value;
--- linux-2.6.7/arch/ppc64/kernel/time.c 2004-06-16 00:20:03.000000000 -0500
+++ linux-2.6.7_seclvl/arch/ppc64/kernel/time.c 2004-08-05 10:32:11.000000000 -0500
@@ -434,9 +434,7 @@
{
int value;
struct timespec myTimeval;
-
- if (!capable(CAP_SYS_TIME))
- return -EPERM;
+ int err;
if (get_user(value, tptr))
return -EFAULT;
@@ -444,6 +442,10 @@
myTimeval.tv_sec = value;
myTimeval.tv_nsec = 0;
+ err = security_settime(&myTimeval, NULL);
+ if (err)
+ return err;
+
do_settimeofday(&myTimeval);
return 0;
@@ -459,9 +461,7 @@
{
long value;
struct timespec myTimeval;
-
- if (!capable(CAP_SYS_TIME))
- return -EPERM;
+ int err;
if (get_user(value, tptr))
return -EFAULT;
@@ -469,6 +469,10 @@
myTimeval.tv_sec = value;
myTimeval.tv_nsec = 0;
+ err = security_settime(&myTimeval, NULL);
+ if (err)
+ return err;
+
do_settimeofday(&myTimeval);
return 0;
--- linux-2.6.7/include/linux/security.h 2004-06-16 00:19:43.000000000 -0500
+++ linux-2.6.7_seclvl/include/linux/security.h 2004-08-05 10:32:11.000000000 -0500
@@ -39,6 +39,7 @@
* as the default capabilities functions
*/
extern int cap_capable (struct task_struct *tsk, int cap);
+extern int cap_settime (struct timespec *ts, struct timezone *tz);
extern int cap_ptrace (struct task_struct *parent, struct task_struct *child);
extern int cap_capget (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
extern int cap_capset_check (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
@@ -996,6 +997,12 @@
* See the syslog(2) manual page for an explanation of the @type values.
* @type contains the type of action.
* Return 0 if permission is granted.
+ * @settime:
+ * Check permission to change the system time.
+ * struct timespec and timezone are defined in include/linux/time.h
+ * @ts contains new time
+ * @tz contains new timezone
+ * Return 0 if permission is granted.
* @vm_enough_memory:
* Check permissions for allocating a new virtual mapping.
* @pages contains the number of pages.
@@ -1031,6 +1038,7 @@
int (*quotactl) (int cmds, int type, int id, struct super_block * sb);
int (*quota_on) (struct file * f);
int (*syslog) (int type);
+ int (*settime) (struct timespec *ts, struct timezone *tz);
int (*vm_enough_memory) (long pages);
int (*bprm_alloc_security) (struct linux_binprm * bprm);
@@ -1286,6 +1294,12 @@
return security_ops->syslog(type);
}
+static inline int security_settime(struct timespec *ts, struct timezone *tz)
+{
+ return security_ops->settime(ts, tz);
+}
+
+
static inline int security_vm_enough_memory(long pages)
{
return security_ops->vm_enough_memory(pages);
@@ -1958,6 +1972,11 @@
return cap_syslog(type);
}
+static inline int security_settime(struct timespec *ts, struct timezone *tz)
+{
+ return cap_settime(ts, tz);
+}
+
static inline int security_vm_enough_memory(long pages)
{
return cap_vm_enough_memory(pages);
--- linux-2.6.7/kernel/time.c 2004-06-16 00:19:01.000000000 -0500
+++ linux-2.6.7_seclvl/kernel/time.c 2004-08-05 10:32:11.000000000 -0500
@@ -28,6 +28,7 @@
#include <linux/timex.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
+#include <linux/security.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -74,13 +75,17 @@
asmlinkage long sys_stime(time_t __user *tptr)
{
struct timespec tv;
+ int err;
- if (!capable(CAP_SYS_TIME))
- return -EPERM;
if (get_user(tv.tv_sec, tptr))
return -EFAULT;
tv.tv_nsec = 0;
+
+ err = security_settime(&tv, NULL);
+ if (err)
+ return err;
+
do_settimeofday(&tv);
return 0;
}
@@ -142,10 +147,13 @@
int do_sys_settimeofday(struct timespec *tv, struct timezone *tz)
{
static int firsttime = 1;
+ int error = 0;
+
+ /* Call the Linux Security Module to perform its checks */
+ error = security_settime(tv, tz);
+ if (error)
+ return error;
- if (!capable(CAP_SYS_TIME))
- return -EPERM;
-
if (tz) {
/* SMP safe, global irq locking makes it work. */
sys_tz = *tz;
--- linux-2.6.7/security/capability.c 2004-06-16 00:19:13.000000000 -0500
+++ linux-2.6.7_seclvl/security/capability.c 2004-08-05 10:32:11.000000000 -0500
@@ -30,6 +30,7 @@
.capset_check = cap_capset_check,
.capset_set = cap_capset_set,
.capable = cap_capable,
+ .settime = cap_settime,
.netlink_send = cap_netlink_send,
.netlink_recv = cap_netlink_recv,
--- linux-2.6.7/security/commoncap.c 2004-06-16 00:19:13.000000000 -0500
+++ linux-2.6.7_seclvl/security/commoncap.c 2004-08-05 10:32:11.000000000 -0500
@@ -33,6 +33,14 @@
return -EPERM;
}
+int cap_settime(struct timespec *ts, struct timezone *tz)
+{
+ if (!capable (CAP_SYS_TIME))
+ return -EPERM;
+ else
+ return 0;
+}
+
int cap_ptrace (struct task_struct *parent, struct task_struct *child)
{
/* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
@@ -368,6 +376,7 @@
}
EXPORT_SYMBOL(cap_capable);
+EXPORT_SYMBOL(cap_settime);
EXPORT_SYMBOL(cap_ptrace);
EXPORT_SYMBOL(cap_capget);
EXPORT_SYMBOL(cap_capset_check);
--- linux-2.6.7/security/dummy.c 2004-06-16 00:19:01.000000000 -0500
+++ linux-2.6.7_seclvl/security/dummy.c 2004-08-05 10:32:11.000000000 -0500
@@ -104,6 +104,13 @@
return 0;
}
+static int dummy_settime (struct timeval *tv, struct timezone *tz)
+{
+ if (!capable (CAP_SYS_TIME))
+ return -EPERM;
+ return 0;
+}
+
/*
* Check that a process has enough memory to allocate a new virtual
* mapping. 0 means there is enough memory for the allocation to
@@ -897,6 +904,7 @@
set_to_dummy_if_null(ops, quota_on);
set_to_dummy_if_null(ops, sysctl);
set_to_dummy_if_null(ops, syslog);
+ set_to_dummy_if_null(ops, settime);
set_to_dummy_if_null(ops, vm_enough_memory);
set_to_dummy_if_null(ops, bprm_alloc_security);
set_to_dummy_if_null(ops, bprm_free_security);