Commit cdb16df9 authored by Michael A. Halcrow's avatar Michael A. Halcrow Committed by Linus Torvalds

[PATCH] BSD Secure Levels LSM: add time hooks

I have received positive feedback from various individuals who have applied my
BSD Secure Levels LSM patch, and so at this point I am submitting it to you
with a request to merge it in.  Nothing has changed in this patch since when I
last posted it to the LKML, so I am not re-sending it there.

This first patch adds hooks to catch attempts to set the system clock back.
Signed-off-by: default avatarMichael A. Halcrow <mahalcro@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 26d78497
...@@ -619,8 +619,14 @@ asmlinkage int irix_getgid(struct pt_regs *regs) ...@@ -619,8 +619,14 @@ asmlinkage int irix_getgid(struct pt_regs *regs)
asmlinkage int irix_stime(int value) asmlinkage int irix_stime(int value)
{ {
if (!capable(CAP_SYS_TIME)) int err;
return -EPERM; struct timespec tv;
tv.tv_sec = value;
tv.tv_nsec = 0;
err = security_settime(&tv, NULL);
if (err)
return err;
write_seqlock_irq(&xtime_lock); write_seqlock_irq(&xtime_lock);
xtime.tv_sec = value; xtime.tv_sec = value;
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/profile.h> #include <linux/profile.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/security.h>
#include <asm/segment.h> #include <asm/segment.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -434,9 +435,7 @@ long ppc64_sys32_stime(int __user * tptr) ...@@ -434,9 +435,7 @@ long ppc64_sys32_stime(int __user * tptr)
{ {
int value; int value;
struct timespec myTimeval; struct timespec myTimeval;
int err;
if (!capable(CAP_SYS_TIME))
return -EPERM;
if (get_user(value, tptr)) if (get_user(value, tptr))
return -EFAULT; return -EFAULT;
...@@ -444,6 +443,10 @@ long ppc64_sys32_stime(int __user * tptr) ...@@ -444,6 +443,10 @@ long ppc64_sys32_stime(int __user * tptr)
myTimeval.tv_sec = value; myTimeval.tv_sec = value;
myTimeval.tv_nsec = 0; myTimeval.tv_nsec = 0;
err = security_settime(&myTimeval, NULL);
if (err)
return err;
do_settimeofday(&myTimeval); do_settimeofday(&myTimeval);
return 0; return 0;
...@@ -459,9 +462,7 @@ long ppc64_sys_stime(long __user * tptr) ...@@ -459,9 +462,7 @@ long ppc64_sys_stime(long __user * tptr)
{ {
long value; long value;
struct timespec myTimeval; struct timespec myTimeval;
int err;
if (!capable(CAP_SYS_TIME))
return -EPERM;
if (get_user(value, tptr)) if (get_user(value, tptr))
return -EFAULT; return -EFAULT;
...@@ -469,6 +470,10 @@ long ppc64_sys_stime(long __user * tptr) ...@@ -469,6 +470,10 @@ long ppc64_sys_stime(long __user * tptr)
myTimeval.tv_sec = value; myTimeval.tv_sec = value;
myTimeval.tv_nsec = 0; myTimeval.tv_nsec = 0;
err = security_settime(&myTimeval, NULL);
if (err)
return err;
do_settimeofday(&myTimeval); do_settimeofday(&myTimeval);
return 0; return 0;
......
...@@ -40,6 +40,7 @@ struct ctl_table; ...@@ -40,6 +40,7 @@ struct ctl_table;
* as the default capabilities functions * as the default capabilities functions
*/ */
extern int cap_capable (struct task_struct *tsk, int cap); 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_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_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); extern int cap_capset_check (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
...@@ -1001,6 +1002,12 @@ struct swap_info_struct; ...@@ -1001,6 +1002,12 @@ struct swap_info_struct;
* See the syslog(2) manual page for an explanation of the @type values. * See the syslog(2) manual page for an explanation of the @type values.
* @type contains the type of action. * @type contains the type of action.
* Return 0 if permission is granted. * 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: * @vm_enough_memory:
* Check permissions for allocating a new virtual mapping. * Check permissions for allocating a new virtual mapping.
* @pages contains the number of pages. * @pages contains the number of pages.
...@@ -1036,6 +1043,7 @@ struct security_operations { ...@@ -1036,6 +1043,7 @@ struct security_operations {
int (*quotactl) (int cmds, int type, int id, struct super_block * sb); int (*quotactl) (int cmds, int type, int id, struct super_block * sb);
int (*quota_on) (struct file * f); int (*quota_on) (struct file * f);
int (*syslog) (int type); int (*syslog) (int type);
int (*settime) (struct timespec *ts, struct timezone *tz);
int (*vm_enough_memory) (long pages); int (*vm_enough_memory) (long pages);
int (*bprm_alloc_security) (struct linux_binprm * bprm); int (*bprm_alloc_security) (struct linux_binprm * bprm);
...@@ -1291,6 +1299,12 @@ static inline int security_syslog(int type) ...@@ -1291,6 +1299,12 @@ static inline int security_syslog(int type)
return security_ops->syslog(type); 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) static inline int security_vm_enough_memory(long pages)
{ {
return security_ops->vm_enough_memory(pages); return security_ops->vm_enough_memory(pages);
...@@ -1963,6 +1977,11 @@ static inline int security_syslog(int type) ...@@ -1963,6 +1977,11 @@ static inline int security_syslog(int type)
return cap_syslog(type); 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) static inline int security_vm_enough_memory(long pages)
{ {
return cap_vm_enough_memory(pages); return cap_vm_enough_memory(pages);
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/security.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/unistd.h> #include <asm/unistd.h>
...@@ -78,13 +80,17 @@ asmlinkage long sys_time(int __user * tloc) ...@@ -78,13 +80,17 @@ asmlinkage long sys_time(int __user * tloc)
asmlinkage long sys_stime(time_t __user *tptr) asmlinkage long sys_stime(time_t __user *tptr)
{ {
struct timespec tv; struct timespec tv;
int err;
if (!capable(CAP_SYS_TIME))
return -EPERM;
if (get_user(tv.tv_sec, tptr)) if (get_user(tv.tv_sec, tptr))
return -EFAULT; return -EFAULT;
tv.tv_nsec = 0; tv.tv_nsec = 0;
err = security_settime(&tv, NULL);
if (err)
return err;
do_settimeofday(&tv); do_settimeofday(&tv);
return 0; return 0;
} }
...@@ -146,10 +152,12 @@ inline static void warp_clock(void) ...@@ -146,10 +152,12 @@ inline static void warp_clock(void)
int do_sys_settimeofday(struct timespec *tv, struct timezone *tz) int do_sys_settimeofday(struct timespec *tv, struct timezone *tz)
{ {
static int firsttime = 1; static int firsttime = 1;
int error = 0;
error = security_settime(tv, tz);
if (error)
return error;
if (!capable(CAP_SYS_TIME))
return -EPERM;
if (tz) { if (tz) {
/* SMP safe, global irq locking makes it work. */ /* SMP safe, global irq locking makes it work. */
sys_tz = *tz; sys_tz = *tz;
......
...@@ -30,6 +30,7 @@ static struct security_operations capability_ops = { ...@@ -30,6 +30,7 @@ static struct security_operations capability_ops = {
.capset_check = cap_capset_check, .capset_check = cap_capset_check,
.capset_set = cap_capset_set, .capset_set = cap_capset_set,
.capable = cap_capable, .capable = cap_capable,
.settime = cap_settime,
.netlink_send = cap_netlink_send, .netlink_send = cap_netlink_send,
.netlink_recv = cap_netlink_recv, .netlink_recv = cap_netlink_recv,
......
...@@ -27,20 +27,25 @@ ...@@ -27,20 +27,25 @@
int cap_capable (struct task_struct *tsk, int cap) int cap_capable (struct task_struct *tsk, int cap)
{ {
/* Derived from include/linux/sched.h:capable. */ /* Derived from include/linux/sched.h:capable. */
if (cap_raised (tsk->cap_effective, cap)) if (cap_raised(tsk->cap_effective, cap))
return 0; return 0;
else return -EPERM;
}
int cap_settime(struct timespec *ts, struct timezone *tz)
{
if (!capable(CAP_SYS_TIME))
return -EPERM; return -EPERM;
return 0;
} }
int cap_ptrace (struct task_struct *parent, struct task_struct *child) int cap_ptrace (struct task_struct *parent, struct task_struct *child)
{ {
/* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */ /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
if (!cap_issubset (child->cap_permitted, current->cap_permitted) && if (!cap_issubset (child->cap_permitted, current->cap_permitted) &&
!capable (CAP_SYS_PTRACE)) !capable(CAP_SYS_PTRACE))
return -EPERM; return -EPERM;
else return 0;
return 0;
} }
int cap_capget (struct task_struct *target, kernel_cap_t *effective, int cap_capget (struct task_struct *target, kernel_cap_t *effective,
...@@ -373,6 +378,7 @@ int cap_vm_enough_memory(long pages) ...@@ -373,6 +378,7 @@ int cap_vm_enough_memory(long pages)
} }
EXPORT_SYMBOL(cap_capable); EXPORT_SYMBOL(cap_capable);
EXPORT_SYMBOL(cap_settime);
EXPORT_SYMBOL(cap_ptrace); EXPORT_SYMBOL(cap_ptrace);
EXPORT_SYMBOL(cap_capget); EXPORT_SYMBOL(cap_capget);
EXPORT_SYMBOL(cap_capset_check); EXPORT_SYMBOL(cap_capset_check);
......
...@@ -104,6 +104,13 @@ static int dummy_syslog (int type) ...@@ -104,6 +104,13 @@ static int dummy_syslog (int type)
return 0; return 0;
} }
static int dummy_settime(struct timespec *ts, struct timezone *tz)
{
if (!capable(CAP_SYS_TIME))
return -EPERM;
return 0;
}
/* /*
* Check that a process has enough memory to allocate a new virtual * Check that a process has enough memory to allocate a new virtual
* mapping. 0 means there is enough memory for the allocation to * mapping. 0 means there is enough memory for the allocation to
...@@ -897,6 +904,7 @@ void security_fixup_ops (struct security_operations *ops) ...@@ -897,6 +904,7 @@ void security_fixup_ops (struct security_operations *ops)
set_to_dummy_if_null(ops, quota_on); set_to_dummy_if_null(ops, quota_on);
set_to_dummy_if_null(ops, sysctl); set_to_dummy_if_null(ops, sysctl);
set_to_dummy_if_null(ops, syslog); 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, vm_enough_memory);
set_to_dummy_if_null(ops, bprm_alloc_security); set_to_dummy_if_null(ops, bprm_alloc_security);
set_to_dummy_if_null(ops, bprm_free_security); set_to_dummy_if_null(ops, bprm_free_security);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment