diff options
Diffstat (limited to 'security')
-rw-r--r-- | security/commoncap.c | 2 | ||||
-rw-r--r-- | security/selinux/avc.c | 15 | ||||
-rw-r--r-- | security/selinux/hooks.c | 53 | ||||
-rw-r--r-- | security/selinux/include/av_perm_to_string.h | 3 | ||||
-rw-r--r-- | security/selinux/include/av_permissions.h | 3 | ||||
-rw-r--r-- | security/selinux/include/avc.h | 6 | ||||
-rw-r--r-- | security/selinux/include/class_to_string.h | 1 | ||||
-rw-r--r-- | security/selinux/include/flask.h | 1 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 134 | ||||
-rw-r--r-- | security/smack/smackfs.c | 61 |
10 files changed, 208 insertions, 71 deletions
diff --git a/security/commoncap.c b/security/commoncap.c index 5aba82679a0..bb0c095f576 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -552,7 +552,7 @@ int cap_task_kill(struct task_struct *p, struct siginfo *info, * allowed. * We must preserve legacy signal behavior in this case. */ - if (p->euid == 0 && p->uid == current->uid) + if (p->uid == current->uid) return 0; /* sigcont is permitted within same session */ diff --git a/security/selinux/avc.c b/security/selinux/avc.c index e8529e2f51e..187964e88af 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -568,10 +568,11 @@ void avc_audit(u32 ssid, u32 tsid, audit_log_format(ab, " capability=%d", a->u.cap); break; case AVC_AUDIT_DATA_FS: - if (a->u.fs.dentry) { - struct dentry *dentry = a->u.fs.dentry; - if (a->u.fs.mnt) { - audit_log_d_path(ab, "path=", dentry, a->u.fs.mnt); + if (a->u.fs.path.dentry) { + struct dentry *dentry = a->u.fs.path.dentry; + if (a->u.fs.path.mnt) { + audit_log_d_path(ab, "path=", + &a->u.fs.path); } else { audit_log_format(ab, " name="); audit_log_untrustedstring(ab, dentry->d_name.name); @@ -626,8 +627,12 @@ void avc_audit(u32 ssid, u32 tsid, case AF_UNIX: u = unix_sk(sk); if (u->dentry) { + struct path path = { + .dentry = u->dentry, + .mnt = u->mnt + }; audit_log_d_path(ab, "path=", - u->dentry, u->mnt); + &path); break; } if (!u->addr) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index e5ed0751030..75c2e99bfb8 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1272,12 +1272,18 @@ static int task_has_perm(struct task_struct *tsk1, SECCLASS_PROCESS, perms, NULL); } +#if CAP_LAST_CAP > 63 +#error Fix SELinux to handle capabilities > 63. +#endif + /* Check whether a task is allowed to use a capability. */ static int task_has_capability(struct task_struct *tsk, int cap) { struct task_security_struct *tsec; struct avc_audit_data ad; + u16 sclass; + u32 av = CAP_TO_MASK(cap); tsec = tsk->security; @@ -1285,8 +1291,19 @@ static int task_has_capability(struct task_struct *tsk, ad.tsk = tsk; ad.u.cap = cap; - return avc_has_perm(tsec->sid, tsec->sid, - SECCLASS_CAPABILITY, CAP_TO_MASK(cap), &ad); + switch (CAP_TO_INDEX(cap)) { + case 0: + sclass = SECCLASS_CAPABILITY; + break; + case 1: + sclass = SECCLASS_CAPABILITY2; + break; + default: + printk(KERN_ERR + "SELinux: out of range capability %d\n", cap); + BUG(); + } + return avc_has_perm(tsec->sid, tsec->sid, sclass, av, &ad); } /* Check whether a task is allowed to use a system operation. */ @@ -1339,8 +1356,8 @@ static inline int dentry_has_perm(struct task_struct *tsk, struct inode *inode = dentry->d_inode; struct avc_audit_data ad; AVC_AUDIT_DATA_INIT(&ad,FS); - ad.u.fs.mnt = mnt; - ad.u.fs.dentry = dentry; + ad.u.fs.path.mnt = mnt; + ad.u.fs.path.dentry = dentry; return inode_has_perm(tsk, inode, av, &ad); } @@ -1358,15 +1375,12 @@ static int file_has_perm(struct task_struct *tsk, { struct task_security_struct *tsec = tsk->security; struct file_security_struct *fsec = file->f_security; - struct vfsmount *mnt = file->f_path.mnt; - struct dentry *dentry = file->f_path.dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; struct avc_audit_data ad; int rc; AVC_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.mnt = mnt; - ad.u.fs.dentry = dentry; + ad.u.fs.path = file->f_path; if (tsec->sid != fsec->sid) { rc = avc_has_perm(tsec->sid, fsec->sid, @@ -1401,7 +1415,7 @@ static int may_create(struct inode *dir, sbsec = dir->i_sb->s_security; AVC_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.dentry = dentry; + ad.u.fs.path.dentry = dentry; rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR, DIR__ADD_NAME | DIR__SEARCH, @@ -1459,7 +1473,7 @@ static int may_link(struct inode *dir, isec = dentry->d_inode->i_security; AVC_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.dentry = dentry; + ad.u.fs.path.dentry = dentry; av = DIR__SEARCH; av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); @@ -1506,7 +1520,7 @@ static inline int may_rename(struct inode *old_dir, AVC_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.dentry = old_dentry; + ad.u.fs.path.dentry = old_dentry; rc = avc_has_perm(tsec->sid, old_dsec->sid, SECCLASS_DIR, DIR__REMOVE_NAME | DIR__SEARCH, &ad); if (rc) @@ -1522,7 +1536,7 @@ static inline int may_rename(struct inode *old_dir, return rc; } - ad.u.fs.dentry = new_dentry; + ad.u.fs.path.dentry = new_dentry; av = DIR__ADD_NAME | DIR__SEARCH; if (new_dentry->d_inode) av |= DIR__REMOVE_NAME; @@ -1901,8 +1915,7 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm) } AVC_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.mnt = bprm->file->f_path.mnt; - ad.u.fs.dentry = bprm->file->f_path.dentry; + ad.u.fs.path = bprm->file->f_path; if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) newsid = tsec->sid; @@ -2298,7 +2311,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data) return rc; AVC_AUDIT_DATA_INIT(&ad,FS); - ad.u.fs.dentry = sb->s_root; + ad.u.fs.path.dentry = sb->s_root; return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad); } @@ -2307,7 +2320,7 @@ static int selinux_sb_statfs(struct dentry *dentry) struct avc_audit_data ad; AVC_AUDIT_DATA_INIT(&ad,FS); - ad.u.fs.dentry = dentry->d_sb->s_root; + ad.u.fs.path.dentry = dentry->d_sb->s_root; return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad); } @@ -2324,10 +2337,10 @@ static int selinux_mount(char * dev_name, return rc; if (flags & MS_REMOUNT) - return superblock_has_perm(current, nd->mnt->mnt_sb, + return superblock_has_perm(current, nd->path.mnt->mnt_sb, FILESYSTEM__REMOUNT, NULL); else - return dentry_has_perm(current, nd->mnt, nd->dentry, + return dentry_has_perm(current, nd->path.mnt, nd->path.dentry, FILE__MOUNTON); } @@ -2570,7 +2583,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value return -EPERM; AVC_AUDIT_DATA_INIT(&ad,FS); - ad.u.fs.dentry = dentry; + ad.u.fs.path.dentry = dentry; rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass, FILE__RELABELFROM, &ad); diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h index 399f868c5c8..d5696690d3a 100644 --- a/security/selinux/include/av_perm_to_string.h +++ b/security/selinux/include/av_perm_to_string.h @@ -132,6 +132,9 @@ S_(SECCLASS_CAPABILITY, CAPABILITY__LEASE, "lease") S_(SECCLASS_CAPABILITY, CAPABILITY__AUDIT_WRITE, "audit_write") S_(SECCLASS_CAPABILITY, CAPABILITY__AUDIT_CONTROL, "audit_control") + S_(SECCLASS_CAPABILITY, CAPABILITY__SETFCAP, "setfcap") + S_(SECCLASS_CAPABILITY2, CAPABILITY2__MAC_OVERRIDE, "mac_override") + S_(SECCLASS_CAPABILITY2, CAPABILITY2__MAC_ADMIN, "mac_admin") S_(SECCLASS_NETLINK_ROUTE_SOCKET, NETLINK_ROUTE_SOCKET__NLMSG_READ, "nlmsg_read") S_(SECCLASS_NETLINK_ROUTE_SOCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE, "nlmsg_write") S_(SECCLASS_NETLINK_FIREWALL_SOCKET, NETLINK_FIREWALL_SOCKET__NLMSG_READ, "nlmsg_read") diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index 84c9abc8097..75b41311ab8 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h @@ -533,6 +533,9 @@ #define CAPABILITY__LEASE 0x10000000UL #define CAPABILITY__AUDIT_WRITE 0x20000000UL #define CAPABILITY__AUDIT_CONTROL 0x40000000UL +#define CAPABILITY__SETFCAP 0x80000000UL +#define CAPABILITY2__MAC_OVERRIDE 0x00000001UL +#define CAPABILITY2__MAC_ADMIN 0x00000002UL #define NETLINK_ROUTE_SOCKET__IOCTL 0x00000001UL #define NETLINK_ROUTE_SOCKET__READ 0x00000002UL #define NETLINK_ROUTE_SOCKET__WRITE 0x00000004UL diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 80c28fa6621..8e23d7a873a 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -13,6 +13,7 @@ #include <linux/spinlock.h> #include <linux/init.h> #include <linux/in6.h> +#include <linux/path.h> #include <asm/system.h> #include "flask.h" #include "av_permissions.h" @@ -30,8 +31,6 @@ extern int selinux_enforcing; struct avc_entry; struct task_struct; -struct vfsmount; -struct dentry; struct inode; struct sock; struct sk_buff; @@ -46,8 +45,7 @@ struct avc_audit_data { struct task_struct *tsk; union { struct { - struct vfsmount *mnt; - struct dentry *dentry; + struct path path; struct inode *inode; } fs; struct { diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h index b1b0d1d8f95..bd813c366e3 100644 --- a/security/selinux/include/class_to_string.h +++ b/security/selinux/include/class_to_string.h @@ -71,3 +71,4 @@ S_(NULL) S_(NULL) S_("peer") + S_("capability2") diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h index 09e9dd23ee1..febf8868e85 100644 --- a/security/selinux/include/flask.h +++ b/security/selinux/include/flask.h @@ -51,6 +51,7 @@ #define SECCLASS_DCCP_SOCKET 60 #define SECCLASS_MEMPROTECT 61 #define SECCLASS_PEER 68 +#define SECCLASS_CAPABILITY2 69 /* * Security identifier indices for initial entities diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 1c11e424585..770eb067e16 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -325,7 +325,7 @@ static int smack_sb_statfs(struct dentry *dentry) static int smack_sb_mount(char *dev_name, struct nameidata *nd, char *type, unsigned long flags, void *data) { - struct superblock_smack *sbp = nd->mnt->mnt_sb->s_security; + struct superblock_smack *sbp = nd->path.mnt->mnt_sb->s_security; return smk_curacc(sbp->smk_floor, MAY_WRITE); } @@ -584,14 +584,20 @@ static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) static int smack_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags) { - if (!capable(CAP_MAC_ADMIN)) { - if (strcmp(name, XATTR_NAME_SMACK) == 0 || - strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || - strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) - return -EPERM; - } + int rc = 0; - return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE); + if (strcmp(name, XATTR_NAME_SMACK) == 0 || + strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || + strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) { + if (!capable(CAP_MAC_ADMIN)) + rc = -EPERM; + } else + rc = cap_inode_setxattr(dentry, name, value, size, flags); + + if (rc == 0) + rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE); + + return rc; } /** @@ -658,10 +664,20 @@ static int smack_inode_getxattr(struct dentry *dentry, char *name) */ static int smack_inode_removexattr(struct dentry *dentry, char *name) { - if (strcmp(name, XATTR_NAME_SMACK) == 0 && !capable(CAP_MAC_ADMIN)) - return -EPERM; + int rc = 0; - return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE); + if (strcmp(name, XATTR_NAME_SMACK) == 0 || + strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || + strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) { + if (!capable(CAP_MAC_ADMIN)) + rc = -EPERM; + } else + rc = cap_inode_removexattr(dentry, name); + + if (rc == 0) + rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE); + + return rc; } /** @@ -701,7 +717,7 @@ static int smack_inode_getsecurity(const struct inode *inode, return -EOPNOTSUPP; sock = SOCKET_I(ip); - if (sock == NULL) + if (sock == NULL || sock->sk == NULL) return -EOPNOTSUPP; ssp = sock->sk->sk_security; @@ -1016,7 +1032,12 @@ static void smack_task_getsecid(struct task_struct *p, u32 *secid) */ static int smack_task_setnice(struct task_struct *p, int nice) { - return smk_curacc(p->security, MAY_WRITE); + int rc; + + rc = cap_task_setnice(p, nice); + if (rc == 0) + rc = smk_curacc(p->security, MAY_WRITE); + return rc; } /** @@ -1028,7 +1049,12 @@ static int smack_task_setnice(struct task_struct *p, int nice) */ static int smack_task_setioprio(struct task_struct *p, int ioprio) { - return smk_curacc(p->security, MAY_WRITE); + int rc; + + rc = cap_task_setioprio(p, ioprio); + if (rc == 0) + rc = smk_curacc(p->security, MAY_WRITE); + return rc; } /** @@ -1053,7 +1079,12 @@ static int smack_task_getioprio(struct task_struct *p) static int smack_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp) { - return smk_curacc(p->security, MAY_WRITE); + int rc; + + rc = cap_task_setscheduler(p, policy, lp); + if (rc == 0) + rc = smk_curacc(p->security, MAY_WRITE); + return rc; } /** @@ -1093,6 +1124,11 @@ static int smack_task_movememory(struct task_struct *p) static int smack_task_kill(struct task_struct *p, struct siginfo *info, int sig, u32 secid) { + int rc; + + rc = cap_task_kill(p, info, sig, secid); + if (rc != 0) + return rc; /* * Special cases where signals really ought to go through * in spite of policy. Stephen Smalley suggests it may @@ -1251,9 +1287,8 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) switch (smack_net_nltype) { case NETLBL_NLTYPE_CIPSOV4: - nlsp->domain = NULL; - nlsp->flags = NETLBL_SECATTR_DOMAIN; - nlsp->flags |= NETLBL_SECATTR_MLS_LVL; + nlsp->domain = kstrdup(smack, GFP_ATOMIC); + nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; rc = smack_to_cipso(smack, &cipso); if (rc == 0) { @@ -1280,16 +1315,16 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) */ static int smack_netlabel(struct sock *sk) { - struct socket_smack *ssp = sk->sk_security; + struct socket_smack *ssp; struct netlbl_lsm_secattr secattr; - int rc = 0; + int rc; + ssp = sk->sk_security; netlbl_secattr_init(&secattr); smack_to_secattr(ssp->smk_out, &secattr); - if (secattr.flags != NETLBL_SECATTR_NONE) - rc = netlbl_sock_setattr(sk, &secattr); - + rc = netlbl_sock_setattr(sk, &secattr); netlbl_secattr_destroy(&secattr); + return rc; } @@ -1312,6 +1347,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, struct inode_smack *nsp = inode->i_security; struct socket_smack *ssp; struct socket *sock; + int rc = 0; if (value == NULL || size > SMK_LABELLEN) return -EACCES; @@ -1331,7 +1367,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, return -EOPNOTSUPP; sock = SOCKET_I(inode); - if (sock == NULL) + if (sock == NULL || sock->sk == NULL) return -EOPNOTSUPP; ssp = sock->sk->sk_security; @@ -1340,7 +1376,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, ssp->smk_in = sp; else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { ssp->smk_out = sp; - return smack_netlabel(sock->sk); + rc = smack_netlabel(sock->sk); + if (rc != 0) + printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", + __func__, -rc); } else return -EOPNOTSUPP; @@ -1362,7 +1401,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, static int smack_socket_post_create(struct socket *sock, int family, int type, int protocol, int kern) { - if (family != PF_INET) + if (family != PF_INET || sock->sk == NULL) return 0; /* * Set the outbound netlbl. @@ -1775,6 +1814,27 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) return smk_curacc(isp, may); } +/* module stacking operations */ + +/** + * smack_register_security - stack capability module + * @name: module name + * @ops: module operations - ignored + * + * Allow the capability module to register. + */ +static int smack_register_security(const char *name, + struct security_operations *ops) +{ + if (strcmp(name, "capability") != 0) + return -EINVAL; + + printk(KERN_INFO "%s: Registering secondary module %s\n", + __func__, name); + + return 0; +} + /** * smack_d_instantiate - Make sure the blob is correct on an inode * @opt_dentry: unused @@ -2213,6 +2273,9 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent) ssp->smk_packet[0] = '\0'; rc = smack_netlabel(sk); + if (rc != 0) + printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", + __func__, -rc); } /** @@ -2345,6 +2408,20 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) } /* + * smack_secctx_to_secid - return the secid for a smack label + * @secdata: smack label + * @seclen: how long result is + * @secid: outgoing integer + * + * Exists for audit and networking code. + */ +static int smack_secctx_to_secid(char *secdata, u32 seclen, u32 *secid) +{ + *secid = smack_to_secid(secdata); + return 0; +} + +/* * smack_release_secctx - don't do anything. * @key_ref: unused * @context: unused @@ -2392,6 +2469,8 @@ static struct security_operations smack_ops = { .inode_post_setxattr = smack_inode_post_setxattr, .inode_getxattr = smack_inode_getxattr, .inode_removexattr = smack_inode_removexattr, + .inode_need_killpriv = cap_inode_need_killpriv, + .inode_killpriv = cap_inode_killpriv, .inode_getsecurity = smack_inode_getsecurity, .inode_setsecurity = smack_inode_setsecurity, .inode_listsecurity = smack_inode_listsecurity, @@ -2451,6 +2530,8 @@ static struct security_operations smack_ops = { .netlink_send = cap_netlink_send, .netlink_recv = cap_netlink_recv, + .register_security = smack_register_security, + .d_instantiate = smack_d_instantiate, .getprocattr = smack_getprocattr, @@ -2474,6 +2555,7 @@ static struct security_operations smack_ops = { .key_permission = smack_key_permission, #endif /* CONFIG_KEYS */ .secid_to_secctx = smack_secid_to_secctx, + .secctx_to_secid = smack_secctx_to_secid, .release_secctx = smack_release_secctx, }; diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 15aa37f65b3..358c92c1a15 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -24,6 +24,7 @@ #include <net/cipso_ipv4.h> #include <linux/seq_file.h> #include <linux/ctype.h> +#include <linux/audit.h> #include "smack.h" /* @@ -45,6 +46,7 @@ enum smk_inos { */ static DEFINE_MUTEX(smack_list_lock); static DEFINE_MUTEX(smack_cipso_lock); +static DEFINE_MUTEX(smack_ambient_lock); /* * This is the "ambient" label for network traffic. @@ -342,6 +344,9 @@ void smk_cipso_doi(void) struct cipso_v4_doi *doip; struct netlbl_audit audit_info; + audit_info.loginuid = audit_get_loginuid(current); + audit_info.secid = smack_to_secid(current->security); + rc = netlbl_cfg_map_del(NULL, &audit_info); if (rc != 0) printk(KERN_WARNING "%s:%d remove rc = %d\n", @@ -363,6 +368,30 @@ void smk_cipso_doi(void) __func__, __LINE__, rc); } +/** + * smk_unlbl_ambient - initialize the unlabeled domain + */ +void smk_unlbl_ambient(char *oldambient) +{ + int rc; + struct netlbl_audit audit_info; + + audit_info.loginuid = audit_get_loginuid(current); + audit_info.secid = smack_to_secid(current->security); + + if (oldambient != NULL) { + rc = netlbl_cfg_map_del(oldambient, &audit_info); + if (rc != 0) + printk(KERN_WARNING "%s:%d remove rc = %d\n", + __func__, __LINE__, rc); + } + + rc = netlbl_cfg_unlbl_add_map(smack_net_ambient, &audit_info); + if (rc != 0) + printk(KERN_WARNING "%s:%d add rc = %d\n", + __func__, __LINE__, rc); +} + /* * Seq_file read operations for /smack/cipso */ @@ -709,7 +738,6 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf, size_t cn, loff_t *ppos) { ssize_t rc; - char out[SMK_LABELLEN]; int asize; if (*ppos != 0) @@ -717,23 +745,18 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf, /* * Being careful to avoid a problem in the case where * smack_net_ambient gets changed in midstream. - * Since smack_net_ambient is always set with a value - * from the label list, including initially, and those - * never get freed, the worst case is that the pointer - * gets changed just after this strncpy, in which case - * the value passed up is incorrect. Locking around - * smack_net_ambient wouldn't be any better than this - * copy scheme as by the time the caller got to look - * at the ambient value it would have cleared the lock - * and been changed. */ - strncpy(out, smack_net_ambient, SMK_LABELLEN); - asize = strlen(out) + 1; + mutex_lock(&smack_ambient_lock); - if (cn < asize) - return -EINVAL; + asize = strlen(smack_net_ambient) + 1; + + if (cn >= asize) + rc = simple_read_from_buffer(buf, cn, ppos, + smack_net_ambient, asize); + else + rc = -EINVAL; - rc = simple_read_from_buffer(buf, cn, ppos, out, asize); + mutex_unlock(&smack_ambient_lock); return rc; } @@ -751,6 +774,7 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char in[SMK_LABELLEN]; + char *oldambient; char *smack; if (!capable(CAP_MAC_ADMIN)) @@ -766,7 +790,13 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, if (smack == NULL) return -EINVAL; + mutex_lock(&smack_ambient_lock); + + oldambient = smack_net_ambient; smack_net_ambient = smack; + smk_unlbl_ambient(oldambient); + + mutex_unlock(&smack_ambient_lock); return count; } @@ -974,6 +1004,7 @@ static int __init init_smk_fs(void) sema_init(&smack_write_sem, 1); smk_cipso_doi(); + smk_unlbl_ambient(NULL); return err; } |