---------------------------
-What: ide-scsi (BLK_DEV_IDESCSI)
-When: 2.6.29
-Why: The 2.6 kernel supports direct writing to ide CD drives, which
- eliminates the need for ide-scsi. The new method is more
- efficient in every way.
-Who: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-
----------------------------
-
What: i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client()
When: 2.6.29 (ideally) or 2.6.30 (more likely)
Why: Deprecated by the new (standard) device driver binding model. Use
i2c_driver->probe() and ->remove() instead.
Who: Jean Delvare <khali@linux-fr.org>
+
+ ---------------------------
+
+ What: SELinux "compat_net" functionality
+ When: 2.6.30 at the earliest
+ Why: In 2.6.18 the Secmark concept was introduced to replace the "compat_net"
+ network access control functionality of SELinux. Secmark offers both
+ better performance and greater flexibility than the "compat_net"
+ mechanism. Now that the major Linux distributions have moved to
+ Secmark, it is time to deprecate the older mechanism and start the
+ process of removing the old code.
+ Who: Paul Moore <paul.moore@hp.com>
* These functions are in security/capability.c and are used
* as the default capabilities functions
*/
- extern int cap_capable(struct task_struct *tsk, int cap, int audit);
+ extern int cap_capable(struct task_struct *tsk, const struct cred *cred,
+ int cap, int audit);
extern int cap_settime(struct timespec *ts, struct timezone *tz);
extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode);
extern int cap_ptrace_traceme(struct task_struct *parent);
* @dir contains the inode structure of the parent directory of the new link.
* @new_dentry contains the dentry structure for the new link.
* Return 0 if permission is granted.
+ * @path_link:
+ * Check permission before creating a new hard link to a file.
+ * @old_dentry contains the dentry structure for an existing link
+ * to the file.
+ * @new_dir contains the path structure of the parent directory of
+ * the new link.
+ * @new_dentry contains the dentry structure for the new link.
+ * Return 0 if permission is granted.
* @inode_unlink:
* Check the permission to remove a hard link to a file.
* @dir contains the inode structure of parent directory of the file.
* @dentry contains the dentry structure for file to be unlinked.
* Return 0 if permission is granted.
+ * @path_unlink:
+ * Check the permission to remove a hard link to a file.
+ * @dir contains the path structure of parent directory of the file.
+ * @dentry contains the dentry structure for file to be unlinked.
+ * Return 0 if permission is granted.
* @inode_symlink:
* Check the permission to create a symbolic link to a file.
* @dir contains the inode structure of parent directory of the symbolic link.
* @dentry contains the dentry structure of the symbolic link.
* @old_name contains the pathname of file.
* Return 0 if permission is granted.
+ * @path_symlink:
+ * Check the permission to create a symbolic link to a file.
+ * @dir contains the path structure of parent directory of
+ * the symbolic link.
+ * @dentry contains the dentry structure of the symbolic link.
+ * @old_name contains the pathname of file.
+ * Return 0 if permission is granted.
* @inode_mkdir:
* Check permissions to create a new directory in the existing directory
* associated with inode strcture @dir.
* @dentry contains the dentry structure of new directory.
* @mode contains the mode of new directory.
* Return 0 if permission is granted.
+ * @path_mkdir:
+ * Check permissions to create a new directory in the existing directory
+ * associated with path strcture @path.
+ * @dir containst the path structure of parent of the directory
+ * to be created.
+ * @dentry contains the dentry structure of new directory.
+ * @mode contains the mode of new directory.
+ * Return 0 if permission is granted.
* @inode_rmdir:
* Check the permission to remove a directory.
* @dir contains the inode structure of parent of the directory to be removed.
* @dentry contains the dentry structure of directory to be removed.
* Return 0 if permission is granted.
+ * @path_rmdir:
+ * Check the permission to remove a directory.
+ * @dir contains the path structure of parent of the directory to be
+ * removed.
+ * @dentry contains the dentry structure of directory to be removed.
+ * Return 0 if permission is granted.
* @inode_mknod:
* Check permissions when creating a special file (or a socket or a fifo
* file created via the mknod system call). Note that if mknod operation
* @mode contains the mode of the new file.
* @dev contains the device number.
* Return 0 if permission is granted.
+ * @path_mknod:
+ * Check permissions when creating a file. Note that this hook is called
+ * even if mknod operation is being done for a regular file.
+ * @dir contains the path structure of parent of the new file.
+ * @dentry contains the dentry structure of the new file.
+ * @mode contains the mode of the new file.
+ * @dev contains the undecoded device number. Use new_decode_dev() to get
+ * the decoded device number.
+ * Return 0 if permission is granted.
* @inode_rename:
* Check for permission to rename a file or directory.
* @old_dir contains the inode structure for parent of the old link.
* @new_dir contains the inode structure for parent of the new link.
* @new_dentry contains the dentry structure of the new link.
* Return 0 if permission is granted.
+ * @path_rename:
+ * Check for permission to rename a file or directory.
+ * @old_dir contains the path structure for parent of the old link.
+ * @old_dentry contains the dentry structure of the old link.
+ * @new_dir contains the path structure for parent of the new link.
+ * @new_dentry contains the dentry structure of the new link.
+ * Return 0 if permission is granted.
* @inode_readlink:
* Check the permission to read the symbolic link.
* @dentry contains the dentry structure for the file link.
* @dentry contains the dentry structure for the file.
* @attr is the iattr structure containing the new file attributes.
* Return 0 if permission is granted.
+ * @path_truncate:
+ * Check permission before truncating a file.
+ * @path contains the path structure for the file.
+ * @length is the new length of the file.
+ * @time_attrs is the flags passed to do_truncate().
+ * Return 0 if permission is granted.
* @inode_getattr:
* Check permission before obtaining file attributes.
* @mnt is the vfsmount where the dentry was looked up
* @permitted contains the permitted capability set.
* Return 0 and update @new if permission is granted.
* @capable:
- * Check whether the @tsk process has the @cap capability.
+ * Check whether the @tsk process has the @cap capability in the indicated
+ * credentials.
* @tsk contains the task_struct for the process.
+ * @cred contains the credentials to use.
* @cap contains the capability <include/linux/capability.h>.
+ * @audit: Whether to write an audit message or not
* Return 0 if the capability is granted for @tsk.
* @acct:
* Check permission before enabling or disabling process accounting. If
const kernel_cap_t *effective,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted);
- int (*capable) (struct task_struct *tsk, int cap, int audit);
+ int (*capable) (struct task_struct *tsk, const struct cred *cred,
+ int cap, int audit);
int (*acct) (struct file *file);
int (*sysctl) (struct ctl_table *table, int op);
int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
struct super_block *newsb);
int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
+#ifdef CONFIG_SECURITY_PATH
+ int (*path_unlink) (struct path *dir, struct dentry *dentry);
+ int (*path_mkdir) (struct path *dir, struct dentry *dentry, int mode);
+ int (*path_rmdir) (struct path *dir, struct dentry *dentry);
+ int (*path_mknod) (struct path *dir, struct dentry *dentry, int mode,
+ unsigned int dev);
+ int (*path_truncate) (struct path *path, loff_t length,
+ unsigned int time_attrs);
+ int (*path_symlink) (struct path *dir, struct dentry *dentry,
+ const char *old_name);
+ int (*path_link) (struct dentry *old_dentry, struct path *new_dir,
+ struct dentry *new_dentry);
+ int (*path_rename) (struct path *old_dir, struct dentry *old_dentry,
+ struct path *new_dir, struct dentry *new_dentry);
+#endif
+
int (*inode_alloc_security) (struct inode *inode);
void (*inode_free_security) (struct inode *inode);
int (*inode_init_security) (struct inode *inode, struct inode *dir,
const kernel_cap_t *effective,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted);
- int security_capable(struct task_struct *tsk, int cap);
- int security_capable_noaudit(struct task_struct *tsk, int cap);
+ int security_capable(int cap);
+ int security_real_capable(struct task_struct *tsk, int cap);
+ int security_real_capable_noaudit(struct task_struct *tsk, int cap);
int security_acct(struct file *file);
int security_sysctl(struct ctl_table *table, int op);
int security_quotactl(int cmds, int type, int id, struct super_block *sb);
return cap_capset(new, old, effective, inheritable, permitted);
}
- static inline int security_capable(struct task_struct *tsk, int cap)
+ static inline int security_capable(int cap)
{
- return cap_capable(tsk, cap, SECURITY_CAP_AUDIT);
+ return cap_capable(current, current_cred(), cap, SECURITY_CAP_AUDIT);
}
- static inline int security_capable_noaudit(struct task_struct *tsk, int cap)
+ static inline int security_real_capable(struct task_struct *tsk, int cap)
{
- return cap_capable(tsk, cap, SECURITY_CAP_NOAUDIT);
+ int ret;
+
+ rcu_read_lock();
+ ret = cap_capable(tsk, __task_cred(tsk), cap, SECURITY_CAP_AUDIT);
+ rcu_read_unlock();
+ return ret;
+ }
+
+ static inline
+ int security_real_capable_noaudit(struct task_struct *tsk, int cap)
+ {
+ int ret;
+
+ rcu_read_lock();
+ ret = cap_capable(tsk, __task_cred(tsk), cap,
+ SECURITY_CAP_NOAUDIT);
+ rcu_read_unlock();
+ return ret;
}
static inline int security_acct(struct file *file)
#endif /* CONFIG_SECURITY_NETWORK_XFRM */
+#ifdef CONFIG_SECURITY_PATH
+int security_path_unlink(struct path *dir, struct dentry *dentry);
+int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode);
+int security_path_rmdir(struct path *dir, struct dentry *dentry);
+int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
+ unsigned int dev);
+int security_path_truncate(struct path *path, loff_t length,
+ unsigned int time_attrs);
+int security_path_symlink(struct path *dir, struct dentry *dentry,
+ const char *old_name);
+int security_path_link(struct dentry *old_dentry, struct path *new_dir,
+ struct dentry *new_dentry);
+int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
+ struct path *new_dir, struct dentry *new_dentry);
+#else /* CONFIG_SECURITY_PATH */
+static inline int security_path_unlink(struct path *dir, struct dentry *dentry)
+{
+ return 0;
+}
+
+static inline int security_path_mkdir(struct path *dir, struct dentry *dentry,
+ int mode)
+{
+ return 0;
+}
+
+static inline int security_path_rmdir(struct path *dir, struct dentry *dentry)
+{
+ return 0;
+}
+
+static inline int security_path_mknod(struct path *dir, struct dentry *dentry,
+ int mode, unsigned int dev)
+{
+ return 0;
+}
+
+static inline int security_path_truncate(struct path *path, loff_t length,
+ unsigned int time_attrs)
+{
+ return 0;
+}
+
+static inline int security_path_symlink(struct path *dir, struct dentry *dentry,
+ const char *old_name)
+{
+ return 0;
+}
+
+static inline int security_path_link(struct dentry *old_dentry,
+ struct path *new_dir,
+ struct dentry *new_dentry)
+{
+ return 0;
+}
+
+static inline int security_path_rename(struct path *old_dir,
+ struct dentry *old_dentry,
+ struct path *new_dir,
+ struct dentry *new_dentry)
+{
+ return 0;
+}
+#endif /* CONFIG_SECURITY_PATH */
+
#ifdef CONFIG_KEYS
#ifdef CONFIG_SECURITY
if (ret < 0)
goto error;
- ret = audit_log_capset(pid, new, current_cred());
- if (ret < 0)
- return ret;
+ audit_log_capset(pid, new, current_cred());
return commit_creds(new);
BUG();
}
- if (has_capability(current, cap)) {
+ if (security_capable(cap) == 0) {
current->flags |= PF_SUPERPRIV;
return 1;
}
/**
* cap_capable - Determine whether a task has a particular effective capability
* @tsk: The task to query
+ * @cred: The credentials to use
* @cap: The capability to check for
* @audit: Whether to write an audit message or not
*
* Determine whether the nominated task has the specified capability amongst
* its effective set, returning 0 if it does, -ve if it does not.
*
- * NOTE WELL: cap_capable() cannot be used like the kernel's capable()
- * function. That is, it has the reverse semantics: cap_capable() returns 0
- * when a task has a capability, but the kernel's capable() returns 1 for this
- * case.
+ * NOTE WELL: cap_has_capability() cannot be used like the kernel's capable()
+ * and has_capability() functions. That is, it has the reverse semantics:
+ * cap_has_capability() returns 0 when a task has a capability, but the
+ * kernel's capable() and has_capability() returns 1 for this case.
*/
- int cap_capable(struct task_struct *tsk, int cap, int audit)
+ int cap_capable(struct task_struct *tsk, const struct cred *cred, int cap,
+ int audit)
{
- __u32 cap_raised;
-
- /* Derived from include/linux/sched.h:capable. */
- rcu_read_lock();
- cap_raised = cap_raised(__task_cred(tsk)->cap_effective, cap);
- rcu_read_unlock();
- return cap_raised ? 0 : -EPERM;
+ return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
}
/**
/* they are so limited unless the current task has the CAP_SETPCAP
* capability
*/
- if (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
+ if (cap_capable(current, current_cred(), CAP_SETPCAP,
+ SECURITY_CAP_AUDIT) == 0)
return 0;
#endif
return 1;
struct inode *inode = dentry->d_inode;
int error;
- if (!inode->i_op || !inode->i_op->getxattr)
+ if (!inode->i_op->getxattr)
return 0;
error = inode->i_op->getxattr(dentry, XATTR_NAME_CAPS, NULL, 0);
{
struct inode *inode = dentry->d_inode;
- if (!inode->i_op || !inode->i_op->removexattr)
+ if (!inode->i_op->removexattr)
return 0;
return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS);
memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
- if (!inode || !inode->i_op || !inode->i_op->getxattr)
+ if (!inode || !inode->i_op->getxattr)
return -ENODATA;
size = inode->i_op->getxattr((struct dentry *)dentry, XATTR_NAME_CAPS, &caps,
& (new->securebits ^ arg2)) /*[1]*/
|| ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
|| (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
- || (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0) /*[4]*/
+ || (cap_capable(current, current_cred(), CAP_SETPCAP,
+ SECURITY_CAP_AUDIT) != 0) /*[4]*/
/*
* [1] no changing of bits that are locked
* [2] no unlocking of locks
{
int cap_sys_admin = 0;
- if (cap_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT) == 0)
+ if (cap_capable(current, current_cred(), CAP_SYS_ADMIN,
+ SECURITY_CAP_NOAUDIT) == 0)
cap_sys_admin = 1;
return __vm_enough_memory(mm, pages, cap_sys_admin);
}
effective, inheritable, permitted);
}
- int security_capable(struct task_struct *tsk, int cap)
+ int security_capable(int cap)
{
- return security_ops->capable(tsk, cap, SECURITY_CAP_AUDIT);
+ return security_ops->capable(current, current_cred(), cap,
+ SECURITY_CAP_AUDIT);
}
- int security_capable_noaudit(struct task_struct *tsk, int cap)
+ int security_real_capable(struct task_struct *tsk, int cap)
{
- return security_ops->capable(tsk, cap, SECURITY_CAP_NOAUDIT);
+ const struct cred *cred;
+ int ret;
+
+ cred = get_task_cred(tsk);
+ ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_AUDIT);
+ put_cred(cred);
+ return ret;
+ }
+
+ int security_real_capable_noaudit(struct task_struct *tsk, int cap)
+ {
+ const struct cred *cred;
+ int ret;
+
+ cred = get_task_cred(tsk);
+ ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_NOAUDIT);
+ put_cred(cred);
+ return ret;
}
int security_acct(struct file *file)
}
EXPORT_SYMBOL(security_inode_init_security);
+#ifdef CONFIG_SECURITY_PATH
+int security_path_mknod(struct path *path, struct dentry *dentry, int mode,
+ unsigned int dev)
+{
+ if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+ return 0;
+ return security_ops->path_mknod(path, dentry, mode, dev);
+}
+EXPORT_SYMBOL(security_path_mknod);
+
+int security_path_mkdir(struct path *path, struct dentry *dentry, int mode)
+{
+ if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+ return 0;
+ return security_ops->path_mkdir(path, dentry, mode);
+}
+
+int security_path_rmdir(struct path *path, struct dentry *dentry)
+{
+ if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+ return 0;
+ return security_ops->path_rmdir(path, dentry);
+}
+
+int security_path_unlink(struct path *path, struct dentry *dentry)
+{
+ if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+ return 0;
+ return security_ops->path_unlink(path, dentry);
+}
+
+int security_path_symlink(struct path *path, struct dentry *dentry,
+ const char *old_name)
+{
+ if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+ return 0;
+ return security_ops->path_symlink(path, dentry, old_name);
+}
+
+int security_path_link(struct dentry *old_dentry, struct path *new_dir,
+ struct dentry *new_dentry)
+{
+ if (unlikely(IS_PRIVATE(old_dentry->d_inode)))
+ return 0;
+ return security_ops->path_link(old_dentry, new_dir, new_dentry);
+}
+
+int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
+ struct path *new_dir, struct dentry *new_dentry)
+{
+ if (unlikely(IS_PRIVATE(old_dentry->d_inode) ||
+ (new_dentry->d_inode && IS_PRIVATE(new_dentry->d_inode))))
+ return 0;
+ return security_ops->path_rename(old_dir, old_dentry, new_dir,
+ new_dentry);
+}
+
+int security_path_truncate(struct path *path, loff_t length,
+ unsigned int time_attrs)
+{
+ if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+ return 0;
+ return security_ops->path_truncate(path, length, time_attrs);
+}
+#endif
+
int security_inode_create(struct inode *dir, struct dentry *dentry, int mode)
{
if (unlikely(IS_PRIVATE(dir)))
unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
- #ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
- #define SELINUX_COMPAT_NET_VALUE 0
- #else
- #define SELINUX_COMPAT_NET_VALUE 1
- #endif
-
- int selinux_compat_net = SELINUX_COMPAT_NET_VALUE;
+ int selinux_compat_net = 0;
static int __init checkreqprot_setup(char *str)
{
if (sscanf(page, "%d", &new_value) != 1)
goto out;
- selinux_compat_net = new_value ? 1 : 0;
+ if (new_value) {
+ printk(KERN_NOTICE
+ "SELinux: compat_net is deprecated, please use secmark"
+ " instead\n");
+ selinux_compat_net = 1;
+ } else
+ selinux_compat_net = 0;
length = count;
out:
free_page((unsigned long) page);
if (ret) {
ret->i_mode = mode;
- ret->i_uid = ret->i_gid = 0;
- ret->i_blocks = 0;
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
}
return ret;
{
int cpu;
- for (cpu = *idx; cpu < NR_CPUS; ++cpu) {
+ for (cpu = *idx; cpu < nr_cpu_ids; ++cpu) {
if (!cpu_possible(cpu))
continue;
*idx = cpu + 1;
ssp->smk_in = csp;
ssp->smk_out = csp;
+ ssp->smk_labeled = SMACK_CIPSO_SOCKET;
ssp->smk_packet[0] = '\0';
sk->sk_security = ssp;
struct smack_cipso cipso;
int rc;
- switch (smack_net_nltype) {
- case NETLBL_NLTYPE_CIPSOV4:
- nlsp->domain = smack;
- nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
+ nlsp->domain = smack;
+ nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
- rc = smack_to_cipso(smack, &cipso);
- if (rc == 0) {
- nlsp->attr.mls.lvl = cipso.smk_level;
- smack_set_catset(cipso.smk_catset, nlsp);
- } else {
- nlsp->attr.mls.lvl = smack_cipso_direct;
- smack_set_catset(smack, nlsp);
- }
- break;
- default:
- break;
+ rc = smack_to_cipso(smack, &cipso);
+ if (rc == 0) {
+ nlsp->attr.mls.lvl = cipso.smk_level;
+ smack_set_catset(cipso.smk_catset, nlsp);
+ } else {
+ nlsp->attr.mls.lvl = smack_cipso_direct;
+ smack_set_catset(smack, nlsp);
}
}
/**
* smack_netlabel - Set the secattr on a socket
* @sk: the socket
+ * @labeled: socket label scheme
*
* Convert the outbound smack value (smk_out) to a
* secattr and attach it to the socket.
*
* Returns 0 on success or an error code
*/
- static int smack_netlabel(struct sock *sk)
+ static int smack_netlabel(struct sock *sk, int labeled)
{
struct socket_smack *ssp;
struct netlbl_lsm_secattr secattr;
- int rc;
+ int rc = 0;
ssp = sk->sk_security;
- netlbl_secattr_init(&secattr);
- smack_to_secattr(ssp->smk_out, &secattr);
- rc = netlbl_sock_setattr(sk, &secattr);
- netlbl_secattr_destroy(&secattr);
+ /*
+ * Usually the netlabel code will handle changing the
+ * packet labeling based on the label.
+ * The case of a single label host is different, because
+ * a single label host should never get a labeled packet
+ * even though the label is usually associated with a packet
+ * label.
+ */
+ local_bh_disable();
+ bh_lock_sock_nested(sk);
+
+ if (ssp->smk_out == smack_net_ambient ||
+ labeled == SMACK_UNLABELED_SOCKET)
+ netlbl_sock_delattr(sk);
+ else {
+ netlbl_secattr_init(&secattr);
+ smack_to_secattr(ssp->smk_out, &secattr);
+ rc = netlbl_sock_setattr(sk, &secattr);
+ netlbl_secattr_destroy(&secattr);
+ }
+
+ bh_unlock_sock(sk);
+ local_bh_enable();
+ /*
+ * Remember the label scheme used so that it is not
+ * necessary to do the netlabel setting if it has not
+ * changed the next time through.
+ *
+ * The -EDESTADDRREQ case is an indication that there's
+ * a single level host involved.
+ */
+ if (rc == 0)
+ ssp->smk_labeled = labeled;
return rc;
}
ssp->smk_in = sp;
else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
ssp->smk_out = sp;
- rc = smack_netlabel(sock->sk);
+ rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
if (rc != 0)
printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
__func__, -rc);
/*
* Set the outbound netlbl.
*/
- return smack_netlabel(sock->sk);
+ return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
+ }
+
+
+ /**
+ * smack_host_label - check host based restrictions
+ * @sip: the object end
+ *
+ * looks for host based access restrictions
+ *
+ * This version will only be appropriate for really small
+ * sets of single label hosts. Because of the masking
+ * it cannot shortcut out on the first match. There are
+ * numerious ways to address the problem, but none of them
+ * have been applied here.
+ *
+ * Returns the label of the far end or NULL if it's not special.
+ */
+ static char *smack_host_label(struct sockaddr_in *sip)
+ {
+ struct smk_netlbladdr *snp;
+ char *bestlabel = NULL;
+ struct in_addr *siap = &sip->sin_addr;
+ struct in_addr *liap;
+ struct in_addr *miap;
+ struct in_addr bestmask;
+
+ if (siap->s_addr == 0)
+ return NULL;
+
+ bestmask.s_addr = 0;
+
+ for (snp = smack_netlbladdrs; snp != NULL; snp = snp->smk_next) {
+ liap = &snp->smk_host.sin_addr;
+ miap = &snp->smk_mask;
+ /*
+ * If the addresses match after applying the list entry mask
+ * the entry matches the address. If it doesn't move along to
+ * the next entry.
+ */
+ if ((liap->s_addr & miap->s_addr) !=
+ (siap->s_addr & miap->s_addr))
+ continue;
+ /*
+ * If the list entry mask identifies a single address
+ * it can't get any more specific.
+ */
+ if (miap->s_addr == 0xffffffff)
+ return snp->smk_label;
+ /*
+ * If the list entry mask is less specific than the best
+ * already found this entry is uninteresting.
+ */
+ if ((miap->s_addr | bestmask.s_addr) == bestmask.s_addr)
+ continue;
+ /*
+ * This is better than any entry found so far.
+ */
+ bestmask.s_addr = miap->s_addr;
+ bestlabel = snp->smk_label;
+ }
+
+ return bestlabel;
+ }
+
+ /**
+ * smack_socket_connect - connect access check
+ * @sock: the socket
+ * @sap: the other end
+ * @addrlen: size of sap
+ *
+ * Verifies that a connection may be possible
+ *
+ * Returns 0 on success, and error code otherwise
+ */
+ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
+ int addrlen)
+ {
+ struct socket_smack *ssp = sock->sk->sk_security;
+ char *hostsp;
+ int rc;
+
+ if (sock->sk == NULL || sock->sk->sk_family != PF_INET)
+ return 0;
+
+ if (addrlen < sizeof(struct sockaddr_in))
+ return -EINVAL;
+
+ hostsp = smack_host_label((struct sockaddr_in *)sap);
+ if (hostsp == NULL) {
+ if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
+ return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
+ return 0;
+ }
+
+ rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
+ if (rc != 0)
+ return rc;
+
+ if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
+ return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
+ return 0;
}
/**
if (newsmack == NULL)
return -EINVAL;
+ /*
+ * No process is ever allowed the web ("@") label.
+ */
+ if (newsmack == smack_known_web.smk_known)
+ return -EPERM;
+
new = prepare_creds();
- if (!new)
+ if (new == NULL)
return -ENOMEM;
new->security = newsmack;
commit_creds(new);
return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE);
}
+ /**
+ * smack_socket_sendmsg - Smack check based on destination host
+ * @sock: the socket
+ * @msghdr: the message
+ * @size: the size of the message
+ *
+ * Return 0 if the current subject can write to the destination
+ * host. This is only a question if the destination is a single
+ * label host.
+ */
+ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
+ int size)
+ {
+ struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
+ struct socket_smack *ssp = sock->sk->sk_security;
+ char *hostsp;
+ int rc;
+
+ /*
+ * Perfectly reasonable for this to be NULL
+ */
+ if (sip == NULL || sip->sin_family != PF_INET)
+ return 0;
+
+ hostsp = smack_host_label(sip);
+ if (hostsp == NULL) {
+ if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
+ return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
+ return 0;
+ }
+
+ rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
+ if (rc != 0)
+ return rc;
+
+ if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
+ return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
+
+ return 0;
+
+ }
+
+
/**
* smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat
* pair to smack
static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)
{
char smack[SMK_LABELLEN];
+ char *sp;
int pcat;
- if ((sap->flags & NETLBL_SECATTR_MLS_LVL) == 0) {
+ if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) {
/*
+ * Looks like a CIPSO packet.
* If there are flags but no level netlabel isn't
* behaving the way we expect it to.
*
+ * Get the categories, if any
* Without guidance regarding the smack value
* for the packet fall back on the network
* ambient value.
*/
- strncpy(sip, smack_net_ambient, SMK_MAXLEN);
+ memset(smack, '\0', SMK_LABELLEN);
+ if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0)
+ for (pcat = -1;;) {
+ pcat = netlbl_secattr_catmap_walk(
+ sap->attr.mls.cat, pcat + 1);
+ if (pcat < 0)
+ break;
+ smack_catset_bit(pcat, smack);
+ }
+ /*
+ * If it is CIPSO using smack direct mapping
+ * we are already done. WeeHee.
+ */
+ if (sap->attr.mls.lvl == smack_cipso_direct) {
+ memcpy(sip, smack, SMK_MAXLEN);
+ return;
+ }
+ /*
+ * Look it up in the supplied table if it is not
+ * a direct mapping.
+ */
+ smack_from_cipso(sap->attr.mls.lvl, smack, sip);
return;
}
- /*
- * Get the categories, if any
- */
- memset(smack, '\0', SMK_LABELLEN);
- if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0)
- for (pcat = -1;;) {
- pcat = netlbl_secattr_catmap_walk(sap->attr.mls.cat,
- pcat + 1);
- if (pcat < 0)
- break;
- smack_catset_bit(pcat, smack);
- }
- /*
- * If it is CIPSO using smack direct mapping
- * we are already done. WeeHee.
- */
- if (sap->attr.mls.lvl == smack_cipso_direct) {
- memcpy(sip, smack, SMK_MAXLEN);
+ if ((sap->flags & NETLBL_SECATTR_SECID) != 0) {
+ /*
+ * Looks like a fallback, which gives us a secid.
+ */
+ sp = smack_from_secid(sap->attr.secid);
+ /*
+ * This has got to be a bug because it is
+ * impossible to specify a fallback without
+ * specifying the label, which will ensure
+ * it has a secid, and the only way to get a
+ * secid is from a fallback.
+ */
+ BUG_ON(sp == NULL);
+ strncpy(sip, sp, SMK_MAXLEN);
return;
}
/*
- * Look it up in the supplied table if it is not a direct mapping.
+ * Without guidance regarding the smack value
+ * for the packet fall back on the network
+ * ambient value.
*/
- smack_from_cipso(sap->attr.mls.lvl, smack, sip);
+ strncpy(sip, smack_net_ambient, SMK_MAXLEN);
return;
}
struct netlbl_lsm_secattr secattr;
struct socket_smack *ssp = sk->sk_security;
char smack[SMK_LABELLEN];
+ char *csp;
int rc;
if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
/*
* Translate what netlabel gave us.
*/
- memset(smack, '\0', SMK_LABELLEN);
netlbl_secattr_init(&secattr);
+
rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
- if (rc == 0)
+ if (rc == 0) {
smack_from_secattr(&secattr, smack);
- else
- strncpy(smack, smack_net_ambient, SMK_MAXLEN);
+ csp = smack;
+ } else
+ csp = smack_net_ambient;
+
netlbl_secattr_destroy(&secattr);
+
/*
* Receiving a packet requires that the other end
* be able to write here. Read access is not required.
* This is the simplist possible security model
* for networking.
*/
- rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
+ rc = smk_access(csp, ssp->smk_in, MAY_WRITE);
if (rc != 0)
netlbl_skbuff_err(skb, rc, 0);
return rc;
/*
* Translate what netlabel gave us.
*/
- memset(smack, '\0', SMK_LABELLEN);
netlbl_secattr_init(&secattr);
rc = netlbl_skbuff_getattr(skb, family, &secattr);
if (rc == 0)
ssp->smk_in = ssp->smk_out = current_security();
ssp->smk_packet[0] = '\0';
- rc = smack_netlabel(sk);
+ rc = smack_netlabel(sk, SMACK_CIPSO_SOCKET);
if (rc != 0)
printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
__func__, -rc);
if (skb == NULL)
return -EACCES;
- memset(smack, '\0', SMK_LABELLEN);
netlbl_secattr_init(&skb_secattr);
rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr);
if (rc == 0)
if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
return -EINVAL;
- if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
+ if (op != Audit_equal && op != Audit_not_equal)
return -EINVAL;
*rule = smk_import(rulestr, 0);
* both pointers will point to the same smack_known
* label.
*/
- if (op == AUDIT_EQUAL)
+ if (op == Audit_equal)
return (rule == smack);
- if (op == AUDIT_NOT_EQUAL)
+ if (op == Audit_not_equal)
return (rule != smack);
return 0;
.unix_may_send = smack_unix_may_send,
.socket_post_create = smack_socket_post_create,
+ .socket_connect = smack_socket_connect,
+ .socket_sendmsg = smack_socket_sendmsg,
.socket_sock_rcv_skb = smack_socket_sock_rcv_skb,
.socket_getpeersec_stream = smack_socket_getpeersec_stream,
.socket_getpeersec_dgram = smack_socket_getpeersec_dgram,
/*
* Initialize locks
*/
- spin_lock_init(&smack_known_unset.smk_cipsolock);
spin_lock_init(&smack_known_huh.smk_cipsolock);
spin_lock_init(&smack_known_hat.smk_cipsolock);
spin_lock_init(&smack_known_star.smk_cipsolock);