diff options
| author | Greg Kroah-Hartman <greg@kroah.com> | 2003-02-15 16:54:55 -0800 |
|---|---|---|
| committer | Greg Kroah-Hartman <greg@kroah.com> | 2003-02-15 16:54:55 -0800 |
| commit | 01d7c8a9040d6704dd76f54989309a7aa52c610a (patch) | |
| tree | 24fd977606983fda0c9528e0dfd0b0e63ea90455 | |
| parent | 0a7852523932a5c9d9960ad3c424386f33c5b763 (diff) | |
| parent | 7c9bf63f9a5559811ffdc17e6dc70cb8df4a5bf6 (diff) | |
merge
| -rw-r--r-- | fs/dcache.c | 3 | ||||
| -rw-r--r-- | fs/exportfs/expfs.c | 5 | ||||
| -rw-r--r-- | fs/file_table.c | 35 | ||||
| -rw-r--r-- | fs/namei.c | 9 | ||||
| -rw-r--r-- | fs/nfsd/vfs.c | 9 | ||||
| -rw-r--r-- | fs/super.c | 8 | ||||
| -rw-r--r-- | include/linux/fs.h | 5 | ||||
| -rw-r--r-- | include/linux/security.h | 69 | ||||
| -rw-r--r-- | kernel/ksyms.c | 3 | ||||
| -rw-r--r-- | kernel/printk.c | 7 | ||||
| -rw-r--r-- | kernel/sys.c | 21 | ||||
| -rw-r--r-- | kernel/sysctl.c | 5 | ||||
| -rw-r--r-- | security/capability.c | 10 | ||||
| -rw-r--r-- | security/dummy.c | 33 |
14 files changed, 168 insertions, 54 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index a93b44eb0d84..7cf8868a3c6e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -25,6 +25,7 @@ #include <linux/module.h> #include <linux/mount.h> #include <asm/uaccess.h> +#include <linux/security.h> #define DCACHE_PARANOIA 1 /* #define DCACHE_DEBUG 1 */ @@ -766,6 +767,7 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name) void d_instantiate(struct dentry *entry, struct inode * inode) { if (!list_empty(&entry->d_alias)) BUG(); + security_d_instantiate(entry, inode); spin_lock(&dcache_lock); if (inode) list_add(&entry->d_alias, &inode->i_dentry); @@ -896,6 +898,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) struct dentry *new = NULL; if (inode && S_ISDIR(inode->i_mode)) { + security_d_instantiate(dentry, inode); spin_lock(&dcache_lock); if (!list_empty(&inode->i_dentry)) { new = list_entry(inode->i_dentry.next, struct dentry, d_alias); diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 9a66fe94dc3f..c74c4a628633 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -353,7 +353,7 @@ static int get_name(struct dentry *dentry, char *name, /* * Open the directory ... */ - error = init_private_file(&file, dentry, FMODE_READ); + error = open_private_file(&file, dentry, O_RDONLY); if (error) goto out; error = -EINVAL; @@ -381,8 +381,7 @@ static int get_name(struct dentry *dentry, char *name, } out_close: - if (file.f_op->release) - file.f_op->release(dir, &file); + close_private_file(&file); out: return error; } diff --git a/fs/file_table.c b/fs/file_table.c index f656300a9d6c..e9333d64c781 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -93,23 +93,42 @@ struct file * get_empty_filp(void) /* * Clear and initialize a (private) struct file for the given dentry, - * and call the open function (if any). The caller must verify that - * inode->i_fop is not NULL. + * allocate the security structure, and call the open function (if any). + * The file should be released using close_private_file. */ -int init_private_file(struct file *filp, struct dentry *dentry, int mode) +int open_private_file(struct file *filp, struct dentry *dentry, int flags) { + int error; memset(filp, 0, sizeof(*filp)); eventpoll_init_file(filp); - filp->f_mode = mode; + filp->f_flags = flags; + filp->f_mode = (flags+1) & O_ACCMODE; atomic_set(&filp->f_count, 1); filp->f_dentry = dentry; filp->f_uid = current->fsuid; filp->f_gid = current->fsgid; filp->f_op = dentry->d_inode->i_fop; - if (filp->f_op->open) - return filp->f_op->open(dentry->d_inode, filp); - else - return 0; + error = security_file_alloc(filp); + if (!error) + if (filp->f_op && filp->f_op->open) { + error = filp->f_op->open(dentry->d_inode, filp); + if (error) + security_file_free(filp); + } + return error; +} + +/* + * Release a private file by calling the release function (if any) and + * freeing the security structure. + */ +void close_private_file(struct file *file) +{ + struct inode * inode = file->f_dentry->d_inode; + + if (file->f_op && file->f_op->release) + file->f_op->release(inode, file); + security_file_free(file); } void fput(struct file * file) diff --git a/fs/namei.c b/fs/namei.c index 578ff2461e8e..d420fa6132c6 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -351,10 +351,8 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, i result = dir->i_op->lookup(dir, dentry); if (result) dput(dentry); - else { + else result = dentry; - security_inode_post_lookup(dir, result); - } } up(&dir->i_sem); return result; @@ -887,10 +885,9 @@ struct dentry * lookup_hash(struct qstr *name, struct dentry * base) if (!new) goto out; dentry = inode->i_op->lookup(inode, new); - if (!dentry) { + if (!dentry) dentry = new; - security_inode_post_lookup(inode, dentry); - } else + else dput(new); } out: diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 088ee1438f54..d0d1a132197c 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -426,7 +426,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, { struct dentry *dentry; struct inode *inode; - int flags = O_RDONLY|O_LARGEFILE, mode = FMODE_READ, err; + int flags = O_RDONLY|O_LARGEFILE, err; /* * If we get here, then the client has already done an "open", @@ -463,14 +463,12 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, goto out_nfserr; flags = O_WRONLY|O_LARGEFILE; - mode = FMODE_WRITE; DQUOT_INIT(inode); } - err = init_private_file(filp, dentry, mode); + err = open_private_file(filp, dentry, flags); if (!err) { - filp->f_flags = flags; filp->f_vfsmnt = fhp->fh_export->ex_mnt; } else if (access & MAY_WRITE) put_write_access(inode); @@ -491,8 +489,7 @@ nfsd_close(struct file *filp) struct dentry *dentry = filp->f_dentry; struct inode *inode = dentry->d_inode; - if (filp->f_op->release) - filp->f_op->release(inode, filp); + close_private_file(filp); if (filp->f_mode & FMODE_WRITE) put_write_access(inode); } diff --git a/fs/super.c b/fs/super.c index 3ea26f504679..24e8b30e9b49 100644 --- a/fs/super.c +++ b/fs/super.c @@ -611,6 +611,7 @@ do_kern_mount(const char *fstype, int flags, char *name, void *data) struct file_system_type *type = get_fs_type(fstype); struct super_block *sb = ERR_PTR(-ENOMEM); struct vfsmount *mnt; + int error; if (!type) return ERR_PTR(-ENODEV); @@ -621,6 +622,13 @@ do_kern_mount(const char *fstype, int flags, char *name, void *data) sb = type->get_sb(type, flags, name, data); if (IS_ERR(sb)) goto out_mnt; + error = security_sb_kern_mount(sb); + if (error) { + up_write(&sb->s_umount); + deactivate_super(sb); + sb = ERR_PTR(error); + goto out_mnt; + } mnt->mnt_sb = sb; mnt->mnt_root = dget(sb->s_root); mnt->mnt_mountpoint = sb->s_root; diff --git a/include/linux/fs.h b/include/linux/fs.h index 03e6223b77b3..a7a7c9ea07f7 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -455,7 +455,10 @@ extern spinlock_t files_lock; #define get_file(x) atomic_inc(&(x)->f_count) #define file_count(x) atomic_read(&(x)->f_count) -extern int init_private_file(struct file *, struct dentry *, int); +/* Initialize and open a private file and allocate its security structure. */ +extern int open_private_file(struct file *, struct dentry *, int); +/* Release a private file and free its security structure. */ +extern void close_private_file(struct file *file); #define MAX_NON_LFS ((1UL<<31) - 1) diff --git a/include/linux/security.h b/include/linux/security.h index d2873ec35117..2054cd48eec2 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -62,7 +62,6 @@ static inline int cap_netlink_recv (struct sk_buff *skb) return 0; } - /* * Values used in the task_security_ops calls */ @@ -351,10 +350,6 @@ struct swap_info_struct; * @mnt is the vfsmount where the dentry was looked up * @dentry contains the dentry structure for the file. * Return 0 if permission is granted. - * @inode_post_lookup: - * Set the security attributes for a file after it has been looked up. - * @inode contains the inode structure for parent directory. - * @d contains the dentry structure for the file. * @inode_delete: * @inode contains the inode structure for deleted inode. * This hook is called when a deleted inode is released (i.e. an inode @@ -926,11 +921,23 @@ struct swap_info_struct; * is NULL. * @file contains the file structure for the accounting file (may be NULL). * Return 0 if permission is granted. + * @sysctl: + * Check permission before accessing the @table sysctl variable in the + * manner specified by @op. + * @table contains the ctl_table structure for the sysctl variable. + * @op contains the operation (001 = search, 002 = write, 004 = read). + * Return 0 if permission is granted. * @capable: * Check whether the @tsk process has the @cap capability. * @tsk contains the task_struct for the process. * @cap contains the capability <include/linux/capability.h>. * Return 0 if the capability is granted for @tsk. + * @syslog: + * Check permission before accessing the kernel message ring or changing + * logging to the console. + * 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. * * @register_security: * allow module stacking. @@ -957,9 +964,11 @@ struct security_operations { kernel_cap_t * inheritable, kernel_cap_t * permitted); int (*acct) (struct file * file); + int (*sysctl) (ctl_table * table, int op); int (*capable) (struct task_struct * tsk, int cap); int (*quotactl) (int cmds, int type, int id, struct super_block * sb); int (*quota_on) (struct file * f); + int (*syslog) (int type); int (*bprm_alloc_security) (struct linux_binprm * bprm); void (*bprm_free_security) (struct linux_binprm * bprm); @@ -969,6 +978,7 @@ struct security_operations { int (*sb_alloc_security) (struct super_block * sb); void (*sb_free_security) (struct super_block * sb); + int (*sb_kern_mount) (struct super_block *sb); int (*sb_statfs) (struct super_block * sb); int (*sb_mount) (char *dev_name, struct nameidata * nd, char *type, unsigned long flags, void *data); @@ -1022,7 +1032,6 @@ struct security_operations { int (*inode_permission_lite) (struct inode *inode, int mask); int (*inode_setattr) (struct dentry *dentry, struct iattr *attr); int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry); - void (*inode_post_lookup) (struct inode *inode, struct dentry *d); void (*inode_delete) (struct inode *inode); int (*inode_setxattr) (struct dentry *dentry, char *name, void *value, size_t size, int flags); @@ -1178,6 +1187,11 @@ static inline int security_acct (struct file *file) return security_ops->acct (file); } +static inline int security_sysctl(ctl_table * table, int op) +{ + return security_ops->sysctl(table, op); +} + static inline int security_quotactl (int cmds, int type, int id, struct super_block *sb) { @@ -1189,6 +1203,11 @@ static inline int security_quota_on (struct file * file) return security_ops->quota_on (file); } +static inline int security_syslog(int type) +{ + return security_ops->syslog(type); +} + static inline int security_bprm_alloc (struct linux_binprm *bprm) { return security_ops->bprm_alloc_security (bprm); @@ -1220,6 +1239,11 @@ static inline void security_sb_free (struct super_block *sb) security_ops->sb_free_security (sb); } +static inline int security_sb_kern_mount (struct super_block *sb) +{ + return security_ops->sb_kern_mount (sb); +} + static inline int security_sb_statfs (struct super_block *sb) { return security_ops->sb_statfs (sb); @@ -1426,12 +1450,6 @@ static inline int security_inode_getattr (struct vfsmount *mnt, return security_ops->inode_getattr (mnt, dentry); } -static inline void security_inode_post_lookup (struct inode *inode, - struct dentry *dentry) -{ - security_ops->inode_post_lookup (inode, dentry); -} - static inline void security_inode_delete (struct inode *inode) { security_ops->inode_delete (inode); @@ -1729,6 +1747,11 @@ static inline int security_sem_semop (struct sem_array * sma, return security_ops->sem_semop(sma, sops, nsops, alter); } +static inline void security_d_instantiate (struct dentry *dentry, struct inode *inode) +{ + security_ops->d_instantiate (dentry, inode); +} + static inline int security_netlink_send(struct sk_buff * skb) { return security_ops->netlink_send(skb); @@ -1793,6 +1816,11 @@ static inline int security_acct (struct file *file) return 0; } +static inline int security_sysctl(ctl_table * table, int op) +{ + return 0; +} + static inline int security_quotactl (int cmds, int type, int id, struct super_block * sb) { @@ -1804,6 +1832,11 @@ static inline int security_quota_on (struct file * file) return 0; } +static inline int security_syslog(int type) +{ + return cap_syslog(type); +} + static inline int security_bprm_alloc (struct linux_binprm *bprm) { return 0; @@ -1835,6 +1868,11 @@ static inline int security_sb_alloc (struct super_block *sb) static inline void security_sb_free (struct super_block *sb) { } +static inline int security_sb_kern_mount (struct super_block *sb) +{ + return 0; +} + static inline int security_sb_statfs (struct super_block *sb) { return 0; @@ -2013,10 +2051,6 @@ static inline int security_inode_getattr (struct vfsmount *mnt, return 0; } -static inline void security_inode_post_lookup (struct inode *inode, - struct dentry *dentry) -{ } - static inline void security_inode_delete (struct inode *inode) { } @@ -2300,6 +2334,9 @@ static inline int security_sem_semop (struct sem_array * sma, return 0; } +static inline void security_d_instantiate (struct dentry *dentry, struct inode *inode) +{ } + /* * The netlink capability defaults need to be used inline by default * (rather than hooking into the capability module) to reduce overhead diff --git a/kernel/ksyms.c b/kernel/ksyms.c index f0503df9fe3d..eba2a0195e5c 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -173,7 +173,8 @@ EXPORT_SYMBOL(mark_buffer_dirty); EXPORT_SYMBOL(end_buffer_io_sync); EXPORT_SYMBOL(__mark_inode_dirty); EXPORT_SYMBOL(get_empty_filp); -EXPORT_SYMBOL(init_private_file); +EXPORT_SYMBOL(open_private_file); +EXPORT_SYMBOL(close_private_file); EXPORT_SYMBOL(filp_open); EXPORT_SYMBOL(filp_close); EXPORT_SYMBOL(put_filp); diff --git a/kernel/printk.c b/kernel/printk.c index 9f2eb4b45669..853ac68708ae 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -28,6 +28,7 @@ #include <linux/config.h> #include <linux/delay.h> #include <linux/smp.h> +#include <linux/security.h> #include <asm/uaccess.h> @@ -161,6 +162,10 @@ int do_syslog(int type, char * buf, int len) char c; int error = 0; + error = security_syslog(type); + if (error) + return error; + switch (type) { case 0: /* Close log */ break; @@ -273,8 +278,6 @@ out: asmlinkage long sys_syslog(int type, char * buf, int len) { - if ((type != 3) && !capable(CAP_SYS_ADMIN)) - return -EPERM; return do_syslog(type, buf, len); } diff --git a/kernel/sys.c b/kernel/sys.c index afa6d2fc1372..4a72c1f2beee 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -212,18 +212,25 @@ cond_syscall(sys_delete_module) static int set_one_prio(struct task_struct *p, int niceval, int error) { + int no_nice; + if (p->uid != current->euid && p->uid != current->uid && !capable(CAP_SYS_NICE)) { error = -EPERM; goto out; } - + if (niceval < task_nice(p) && !capable(CAP_SYS_NICE)) { + error = -EACCES; + goto out; + } + no_nice = security_task_setnice(p, niceval); + if (no_nice) { + error = no_nice; + goto out; + } if (error == -ESRCH) error = 0; - if (niceval < task_nice(p) && !capable(CAP_SYS_NICE)) - error = -EACCES; - else - set_user_nice(p, niceval); + set_user_nice(p, niceval); out: return error; } @@ -941,6 +948,10 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) } ok_pgid: + err = security_task_setpgid(p, pgid); + if (err) + goto out; + if (p->pgrp != pgid) { detach_pid(p, PIDTYPE_PGID); p->pgrp = pgid; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c3c96cd208d4..0364833761c4 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -33,6 +33,7 @@ #include <linux/highuid.h> #include <linux/writeback.h> #include <linux/hugetlb.h> +#include <linux/security.h> #include <asm/uaccess.h> #ifdef CONFIG_ROOT_NFS @@ -432,6 +433,10 @@ static int test_perm(int mode, int op) static inline int ctl_perm(ctl_table *table, int op) { + int error; + error = security_sysctl(table, op); + if (error) + return error; return test_perm(table->mode, op); } diff --git a/security/capability.c b/security/capability.c index 5909732acdfc..822af4fc3c08 100644 --- a/security/capability.c +++ b/security/capability.c @@ -262,6 +262,13 @@ void cap_task_reparent_to_init (struct task_struct *p) return; } +int cap_syslog (int type) +{ + if ((type != 3) && !capable(CAP_SYS_ADMIN)) + return -EPERM; + return 0; +} + EXPORT_SYMBOL(cap_capable); EXPORT_SYMBOL(cap_ptrace); EXPORT_SYMBOL(cap_capget); @@ -272,6 +279,7 @@ EXPORT_SYMBOL(cap_bprm_compute_creds); EXPORT_SYMBOL(cap_task_post_setuid); EXPORT_SYMBOL(cap_task_kmod_set_label); EXPORT_SYMBOL(cap_task_reparent_to_init); +EXPORT_SYMBOL(cap_syslog); #ifdef CONFIG_SECURITY @@ -291,6 +299,8 @@ static struct security_operations capability_ops = { .task_post_setuid = cap_task_post_setuid, .task_kmod_set_label = cap_task_kmod_set_label, .task_reparent_to_init = cap_task_reparent_to_init, + + .syslog = cap_syslog, }; #if defined(CONFIG_SECURITY_CAPABILITIES_MODULE) diff --git a/security/dummy.c b/security/dummy.c index 9b450c740bfa..062ae9a7fa2b 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -75,6 +75,11 @@ static int dummy_capable (struct task_struct *tsk, int cap) return -EPERM; } +static int dummy_sysctl (ctl_table * table, int op) +{ + return 0; +} + static int dummy_quotactl (int cmds, int type, int id, struct super_block *sb) { return 0; @@ -85,6 +90,13 @@ static int dummy_quota_on (struct file *f) return 0; } +static int dummy_syslog (int type) +{ + if ((type != 3) && current->euid) + return -EPERM; + return 0; +} + static int dummy_bprm_alloc_security (struct linux_binprm *bprm) { return 0; @@ -120,6 +132,11 @@ static void dummy_sb_free_security (struct super_block *sb) return; } +static int dummy_sb_kern_mount (struct super_block *sb) +{ + return 0; +} + static int dummy_sb_statfs (struct super_block *sb) { return 0; @@ -306,11 +323,6 @@ static int dummy_inode_getattr (struct vfsmount *mnt, struct dentry *dentry) return 0; } -static void dummy_inode_post_lookup (struct inode *ino, struct dentry *d) -{ - return; -} - static void dummy_inode_delete (struct inode *ino) { return; @@ -719,6 +731,12 @@ static int dummy_unregister_security (const char *name, struct security_operatio return -EINVAL; } +static void dummy_d_instantiate (struct dentry *dentry, struct inode *inode) +{ + return; +} + + struct security_operations dummy_security_ops; #define set_to_dummy_if_null(ops, function) \ @@ -740,6 +758,8 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, capable); set_to_dummy_if_null(ops, quotactl); 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, bprm_alloc_security); set_to_dummy_if_null(ops, bprm_free_security); set_to_dummy_if_null(ops, bprm_compute_creds); @@ -747,6 +767,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, bprm_check_security); set_to_dummy_if_null(ops, sb_alloc_security); set_to_dummy_if_null(ops, sb_free_security); + set_to_dummy_if_null(ops, sb_kern_mount); set_to_dummy_if_null(ops, sb_statfs); set_to_dummy_if_null(ops, sb_mount); set_to_dummy_if_null(ops, sb_check_sb); @@ -780,7 +801,6 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, inode_permission_lite); set_to_dummy_if_null(ops, inode_setattr); set_to_dummy_if_null(ops, inode_getattr); - set_to_dummy_if_null(ops, inode_post_lookup); set_to_dummy_if_null(ops, inode_delete); set_to_dummy_if_null(ops, inode_setxattr); set_to_dummy_if_null(ops, inode_getxattr); @@ -839,6 +859,7 @@ void security_fixup_ops (struct security_operations *ops) set_to_dummy_if_null(ops, netlink_recv); set_to_dummy_if_null(ops, register_security); set_to_dummy_if_null(ops, unregister_security); + set_to_dummy_if_null(ops, d_instantiate); #ifdef CONFIG_SECURITY_NETWORK set_to_dummy_if_null(ops, unix_stream_connect); set_to_dummy_if_null(ops, unix_may_send); |
