LWN.net Logo

settime hooks (1/1)

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


Copyright © 2004, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds