This list is closed, nobody may subscribe to it.
| 2007 |
Jan
|
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2009 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
(1) |
Jun
(2) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| 2011 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| 2013 |
Jan
|
Feb
|
Mar
(7) |
Apr
|
May
(7) |
Jun
(7) |
Jul
(26) |
Aug
|
Sep
(7) |
Oct
(1) |
Nov
(35) |
Dec
(18) |
| 2014 |
Jan
(1) |
Feb
(2) |
Mar
(3) |
Apr
|
May
(16) |
Jun
(35) |
Jul
(103) |
Aug
(45) |
Sep
(226) |
Oct
(200) |
Nov
(66) |
Dec
(42) |
| 2015 |
Jan
(47) |
Feb
(3) |
Mar
(6) |
Apr
(14) |
May
(38) |
Jun
(10) |
Jul
(10) |
Aug
(15) |
Sep
(23) |
Oct
(78) |
Nov
(56) |
Dec
(70) |
| 2016 |
Jan
(9) |
Feb
(8) |
Mar
(15) |
Apr
(18) |
May
(78) |
Jun
(39) |
Jul
(3) |
Aug
(136) |
Sep
(134) |
Oct
(19) |
Nov
(48) |
Dec
(30) |
| 2017 |
Jan
(33) |
Feb
(35) |
Mar
(100) |
Apr
(87) |
May
(169) |
Jun
(119) |
Jul
(165) |
Aug
(241) |
Sep
(128) |
Oct
(42) |
Nov
|
Dec
|
|
From: Jan K. <ja...@su...> - 2017-08-02 08:01:19
|
On Tue 01-08-17 16:24:30, Mimi Zohar wrote:
> From: Christoph Hellwig <hc...@ls...>
>
> Add a new ->integrity_read file operation to read data for integrity
> hash collection. This is defined to be equivalent to ->read_iter,
> except that it will be called with the i_rwsem held exclusively.
>
> Signed-off-by: Christoph Hellwig <hc...@ls...>
> Cc: Matthew Garrett <mat...@ne...>
> Cc: Jan Kara <ja...@su...>
> Cc: "Theodore Ts'o" <ty...@mi...>
> Cc: Andreas Dilger <adi...@di...>
> Cc: Jaegeuk Kim <ja...@ke...>
> Cc: Chao Yu <yu...@hu...>
> Cc: Steven Whitehouse <swh...@re...>
> Cc: Bob Peterson <rpe...@re...>
> Cc: David Woodhouse <dw...@in...>
> Cc: Dave Kleikamp <sh...@ke...>
> Cc: Ryusuke Konishi <kon...@la...>
> Cc: Mark Fasheh <mf...@ve...>
> Cc: Joel Becker <jl...@ev...>
> Cc: Richard Weinberger <ri...@no...>
> Cc: "Darrick J. Wong" <dar...@or...>
> Cc: Hugh Dickins <hu...@go...>
> Cc: Chris Mason <cl...@fb...>
> Signed-off-by: Mimi Zohar <zo...@li...>
...
> +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> + struct iov_iter *to)
> +{
> + struct inode *inode = file_inode(iocb->ki_filp);
> + int o_direct = iocb->ki_flags & IOCB_DIRECT;
> +
> + lockdep_assert_held(&inode->i_rwsem);
> + if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> + return -EIO;
> +
> + if (!iov_iter_count(to))
> + return 0; /* skip atime */
> +
> +#ifdef CONFIG_FS_DAX
> + if (IS_DAX(inode))
> + return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> +#endif
> + if (o_direct)
> + return -EINVAL;
> + return generic_file_read_iter(iocb, to);
> +}
I have noticed this o_direct check - why is it only in ext4 and shouldn't
rather higher layers make sure IOCB_DIRECT iocbs cannot reach
.integrity_read() methods?
Honza
--
Jan Kara <ja...@su...>
SUSE Labs, CR
|
|
From: James M. <jm...@na...> - 2017-08-02 07:38:05
|
On Tue, 1 Aug 2017, Roberto Sassu wrote: > On 8/1/2017 12:27 PM, Christoph Hellwig wrote: > > On Tue, Aug 01, 2017 at 12:20:36PM +0200, Roberto Sassu wrote: > > > This patch introduces a parser for RPM packages. It extracts the digests > > > from the RPMTAG_FILEDIGESTS header section and converts them to binary > > > data > > > before adding them to the hash table. > > > > > > The advantage of this data type is that verifiers can determine who > > > produced that data, as headers are signed by Linux distributions vendors. > > > RPM headers signatures can be provided as digest list metadata. > > > > Err, parsing arbitrary file formats has no business in the kernel. > > The benefit of this choice is that no actions are required for > Linux distribution vendors to support the solution I'm proposing, > because they already provide signed digest lists (RPM headers). > > Since the proof of loading a digest list is the digest of the > digest list (included in the list metadata), if RPM headers are > converted to a different format, remote attestation verifiers > cannot check the signature. > > If the concern is security, it would be possible to prevent unsigned > RPM headers from being parsed, if the PGP key type is upstreamed > (adding in CC key...@vg...). It's a security concern and also a layering violation, there should be no need to parse package file formats in the kernel. I'm not really clear on exactly how this patch series works. Can you provide a more concrete explanation of what steps would occur during boot and attestation? -- James Morris <jm...@na...> |
|
From: Mimi Z. <zo...@li...> - 2017-08-01 20:24:58
|
From: Christoph Hellwig <hc...@ls...>
Add a new ->integrity_read file operation to read data for integrity
hash collection. This is defined to be equivalent to ->read_iter,
except that it will be called with the i_rwsem held exclusively.
Signed-off-by: Christoph Hellwig <hc...@ls...>
Cc: Matthew Garrett <mat...@ne...>
Cc: Jan Kara <ja...@su...>
Cc: "Theodore Ts'o" <ty...@mi...>
Cc: Andreas Dilger <adi...@di...>
Cc: Jaegeuk Kim <ja...@ke...>
Cc: Chao Yu <yu...@hu...>
Cc: Steven Whitehouse <swh...@re...>
Cc: Bob Peterson <rpe...@re...>
Cc: David Woodhouse <dw...@in...>
Cc: Dave Kleikamp <sh...@ke...>
Cc: Ryusuke Konishi <kon...@la...>
Cc: Mark Fasheh <mf...@ve...>
Cc: Joel Becker <jl...@ev...>
Cc: Richard Weinberger <ri...@no...>
Cc: "Darrick J. Wong" <dar...@or...>
Cc: Hugh Dickins <hu...@go...>
Cc: Chris Mason <cl...@fb...>
Signed-off-by: Mimi Zohar <zo...@li...>
---
Changelog v5:
- removed ocf2 and gfs2 integrity_read support based on Jan Kara's review.
Changelog v4:
- define ext2/4 specific ->integrity_read functions.
- properly fail file open with O_DIRECT on filesystem not mounted
with "-o dax".
Changelog v3:
- define simple_read_iter_from_buffer
- replace the existing efivarfs ->read method with ->read_iter method.
- squashed other fs definitions of ->integrity_read with this patch.
Changelog v2:
- change iovec to kvec
Changelog v1:
- update the patch description, removing the concept that the presence of
->integrity_read indicates that the file system can support IMA. (Mimi)
fs/btrfs/file.c | 1 +
fs/efivarfs/file.c | 12 +++++++-----
fs/ext2/file.c | 17 +++++++++++++++++
fs/ext4/file.c | 23 +++++++++++++++++++++++
fs/f2fs/file.c | 1 +
fs/jffs2/file.c | 1 +
fs/jfs/file.c | 1 +
fs/libfs.c | 32 ++++++++++++++++++++++++++++++++
fs/nilfs2/file.c | 1 +
fs/ramfs/file-mmu.c | 1 +
fs/ramfs/file-nommu.c | 1 +
fs/ubifs/file.c | 1 +
fs/xfs/xfs_file.c | 21 +++++++++++++++++++++
include/linux/fs.h | 3 +++
mm/shmem.c | 1 +
security/integrity/iint.c | 20 ++++++++++++++------
16 files changed, 126 insertions(+), 11 deletions(-)
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 9e75d8a39aac..2542dc66c85c 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -3125,6 +3125,7 @@ const struct file_operations btrfs_file_operations = {
#endif
.clone_file_range = btrfs_clone_file_range,
.dedupe_file_range = btrfs_dedupe_file_range,
+ .integrity_read = generic_file_read_iter,
};
void btrfs_auto_defrag_exit(void)
diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c
index 5f22e74bbade..17955a92a5b3 100644
--- a/fs/efivarfs/file.c
+++ b/fs/efivarfs/file.c
@@ -64,9 +64,10 @@ static ssize_t efivarfs_file_write(struct file *file,
return bytes;
}
-static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
+static ssize_t efivarfs_file_read_iter(struct kiocb *iocb,
+ struct iov_iter *iter)
{
+ struct file *file = iocb->ki_filp;
struct efivar_entry *var = file->private_data;
unsigned long datasize = 0;
u32 attributes;
@@ -96,8 +97,8 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
goto out_free;
memcpy(data, &attributes, sizeof(attributes));
- size = simple_read_from_buffer(userbuf, count, ppos,
- data, datasize + sizeof(attributes));
+ size = simple_read_iter_from_buffer(iocb, iter, data,
+ datasize + sizeof(attributes));
out_free:
kfree(data);
@@ -174,8 +175,9 @@ efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p)
const struct file_operations efivarfs_file_operations = {
.open = simple_open,
- .read = efivarfs_file_read,
+ .read_iter = efivarfs_file_read_iter,
.write = efivarfs_file_write,
.llseek = no_llseek,
.unlocked_ioctl = efivarfs_file_ioctl,
+ .integrity_read = efivarfs_file_read_iter,
};
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index d34d32bdc944..111069de1973 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
return generic_file_read_iter(iocb, to);
}
+static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
+ struct iov_iter *to)
+{
+ struct inode *inode = file_inode(iocb->ki_filp);
+
+ lockdep_assert_held(&inode->i_rwsem);
+#ifdef CONFIG_FS_DAX
+ if (!iov_iter_count(to))
+ return 0; /* skip atime */
+
+ if (IS_DAX(iocb->ki_filp->f_mapping->host))
+ return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
+#endif
+ return generic_file_read_iter(iocb, to);
+}
+
static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
#ifdef CONFIG_FS_DAX
@@ -216,6 +232,7 @@ const struct file_operations ext2_file_operations = {
.get_unmapped_area = thp_get_unmapped_area,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
+ .integrity_read = ext2_file_integrity_read_iter,
};
const struct inode_operations ext2_file_inode_operations = {
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 58294c9a7e1d..cb423fff935f 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
return generic_file_read_iter(iocb, to);
}
+static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
+ struct iov_iter *to)
+{
+ struct inode *inode = file_inode(iocb->ki_filp);
+ int o_direct = iocb->ki_flags & IOCB_DIRECT;
+
+ lockdep_assert_held(&inode->i_rwsem);
+ if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
+ return -EIO;
+
+ if (!iov_iter_count(to))
+ return 0; /* skip atime */
+
+#ifdef CONFIG_FS_DAX
+ if (IS_DAX(inode))
+ return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
+#endif
+ if (o_direct)
+ return -EINVAL;
+ return generic_file_read_iter(iocb, to);
+}
+
/*
* Called when an inode is released. Note that this is different
* from ext4_file_open: open gets called at every open, but release
@@ -747,6 +769,7 @@ const struct file_operations ext4_file_operations = {
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.fallocate = ext4_fallocate,
+ .integrity_read = ext4_file_integrity_read_iter,
};
const struct inode_operations ext4_file_inode_operations = {
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 2706130c261b..82ea81da0b2d 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -2514,4 +2514,5 @@ const struct file_operations f2fs_file_operations = {
#endif
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
+ .integrity_read = generic_file_read_iter,
};
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index c12476e309c6..5a63034cccf5 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -57,6 +57,7 @@ const struct file_operations jffs2_file_operations =
.mmap = generic_file_readonly_mmap,
.fsync = jffs2_fsync,
.splice_read = generic_file_splice_read,
+ .integrity_read = generic_file_read_iter,
};
/* jffs2_file_inode_operations */
diff --git a/fs/jfs/file.c b/fs/jfs/file.c
index 739492c7a3fd..423512a810e4 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -162,4 +162,5 @@ const struct file_operations jfs_file_operations = {
#ifdef CONFIG_COMPAT
.compat_ioctl = jfs_compat_ioctl,
#endif
+ .integrity_read = generic_file_read_iter,
};
diff --git a/fs/libfs.c b/fs/libfs.c
index 3aabe553fc45..99333264a0a7 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -16,6 +16,7 @@
#include <linux/exportfs.h>
#include <linux/writeback.h>
#include <linux/buffer_head.h> /* sync_mapping_buffers */
+#include <linux/uio.h>
#include <linux/uaccess.h>
@@ -676,6 +677,37 @@ ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
EXPORT_SYMBOL(simple_write_to_buffer);
/**
+ * simple_read_iter_from_buffer - copy data from the buffer to user space
+ * @iocb: struct containing the file, the current position and other info
+ * @to: the user space buffer to read to
+ * @from: the buffer to read from
+ * @available: the size of the buffer
+ *
+ * The simple_read_iter_from_buffer() function reads up to @available bytes
+ * from the current buffer into the user space buffer.
+ *
+ * On success, the current buffer offset is advanced by the number of bytes
+ * read, or a negative value is returned on error.
+ **/
+ssize_t simple_read_iter_from_buffer(struct kiocb *iocb, struct iov_iter *to,
+ const void *from, size_t available)
+{
+ loff_t pos = iocb->ki_pos;
+ size_t ret;
+
+ if (pos < 0)
+ return -EINVAL;
+ if (pos >= available)
+ return 0;
+ ret = copy_to_iter(from + pos, available - pos, to);
+ if (!ret && iov_iter_count(to))
+ return -EFAULT;
+ iocb->ki_pos = pos + ret;
+ return ret;
+}
+EXPORT_SYMBOL(simple_read_iter_from_buffer);
+
+/**
* memory_read_from_buffer - copy data from the buffer
* @to: the kernel space buffer to read to
* @count: the maximum number of bytes to read
diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c
index c5fa3dee72fc..55e058ac487f 100644
--- a/fs/nilfs2/file.c
+++ b/fs/nilfs2/file.c
@@ -150,6 +150,7 @@ const struct file_operations nilfs_file_operations = {
/* .release = nilfs_release_file, */
.fsync = nilfs_sync_file,
.splice_read = generic_file_splice_read,
+ .integrity_read = generic_file_read_iter,
};
const struct inode_operations nilfs_file_inode_operations = {
diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c
index 12af0490322f..4f24d1b589b1 100644
--- a/fs/ramfs/file-mmu.c
+++ b/fs/ramfs/file-mmu.c
@@ -47,6 +47,7 @@ const struct file_operations ramfs_file_operations = {
.splice_write = iter_file_splice_write,
.llseek = generic_file_llseek,
.get_unmapped_area = ramfs_mmu_get_unmapped_area,
+ .integrity_read = generic_file_read_iter,
};
const struct inode_operations ramfs_file_inode_operations = {
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index 2ef7ce75c062..5ee704fa84e0 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -50,6 +50,7 @@ const struct file_operations ramfs_file_operations = {
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.llseek = generic_file_llseek,
+ .integrity_read = generic_file_read_iter,
};
const struct inode_operations ramfs_file_inode_operations = {
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 8cad0b19b404..5e52a315e18b 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1747,4 +1747,5 @@ const struct file_operations ubifs_file_operations = {
#ifdef CONFIG_COMPAT
.compat_ioctl = ubifs_compat_ioctl,
#endif
+ .integrity_read = generic_file_read_iter,
};
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index c4893e226fd8..0a6704b563d6 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -292,6 +292,26 @@ xfs_file_read_iter(
return ret;
}
+static ssize_t
+xfs_integrity_read(
+ struct kiocb *iocb,
+ struct iov_iter *to)
+{
+ struct inode *inode = file_inode(iocb->ki_filp);
+ struct xfs_mount *mp = XFS_I(inode)->i_mount;
+
+ lockdep_assert_held(&inode->i_rwsem);
+
+ XFS_STATS_INC(mp, xs_read_calls);
+
+ if (XFS_FORCED_SHUTDOWN(mp))
+ return -EIO;
+
+ if (IS_DAX(inode))
+ return dax_iomap_rw(iocb, to, &xfs_iomap_ops);
+ return generic_file_read_iter(iocb, to);
+}
+
/*
* Zero any on disk space between the current EOF and the new, larger EOF.
*
@@ -1175,6 +1195,7 @@ const struct file_operations xfs_file_operations = {
.fallocate = xfs_file_fallocate,
.clone_file_range = xfs_file_clone_range,
.dedupe_file_range = xfs_file_dedupe_range,
+ .integrity_read = xfs_integrity_read,
};
const struct file_operations xfs_dir_file_operations = {
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 6e1fd5d21248..8d0d10e1dd93 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1699,6 +1699,7 @@ struct file_operations {
u64);
ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
u64);
+ ssize_t (*integrity_read)(struct kiocb *, struct iov_iter *);
} __randomize_layout;
struct inode_operations {
@@ -3097,6 +3098,8 @@ extern void simple_release_fs(struct vfsmount **mount, int *count);
extern ssize_t simple_read_from_buffer(void __user *to, size_t count,
loff_t *ppos, const void *from, size_t available);
+extern ssize_t simple_read_iter_from_buffer(struct kiocb *iocb,
+ struct iov_iter *to, const void *from, size_t available);
extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
const void __user *from, size_t count);
diff --git a/mm/shmem.c b/mm/shmem.c
index b0aa6075d164..805d99011ca4 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3849,6 +3849,7 @@ static const struct file_operations shmem_file_operations = {
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.fallocate = shmem_fallocate,
+ .integrity_read = shmem_file_read_iter,
#endif
};
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 6fc888ca468e..df04f35a1d40 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -21,6 +21,7 @@
#include <linux/rbtree.h>
#include <linux/file.h>
#include <linux/uaccess.h>
+#include <linux/uio.h>
#include "integrity.h"
static struct rb_root integrity_iint_tree = RB_ROOT;
@@ -184,18 +185,25 @@ security_initcall(integrity_iintcache_init);
int integrity_kernel_read(struct file *file, loff_t offset,
void *addr, unsigned long count)
{
- mm_segment_t old_fs;
- char __user *buf = (char __user *)addr;
+ struct inode *inode = file_inode(file);
+ struct kvec iov = { .iov_base = addr, .iov_len = count };
+ struct kiocb kiocb;
+ struct iov_iter iter;
ssize_t ret;
+ lockdep_assert_held(&inode->i_rwsem);
+
if (!(file->f_mode & FMODE_READ))
return -EBADF;
+ if (!file->f_op->integrity_read)
+ return -EBADF;
- old_fs = get_fs();
- set_fs(get_ds());
- ret = __vfs_read(file, buf, count, &offset);
- set_fs(old_fs);
+ init_sync_kiocb(&kiocb, file);
+ kiocb.ki_pos = offset;
+ iov_iter_kvec(&iter, READ | ITER_KVEC, &iov, 1, count);
+ ret = file->f_op->integrity_read(&kiocb, &iter);
+ BUG_ON(ret == -EIOCBQUEUED);
return ret;
}
--
2.7.4
|
|
From: Tycho A. <ty...@do...> - 2017-08-01 17:45:30
|
Hi Mehmet,
On Thu, Jul 20, 2017 at 06:50:31PM -0400, Mehmet Kayaalp wrote:
> --- a/security/integrity/ima/ima_ns.c
> +++ b/security/integrity/ima/ima_ns.c
> @@ -301,3 +301,24 @@ struct ns_status *ima_get_ns_status(struct ima_namespace *ns,
>
> return status;
> }
> +
> +#define IMA_NS_STATUS_ACTIONS IMA_AUDIT
> +#define IMA_NS_STATUS_FLAGS IMA_AUDITED
> +
Seems like these are defined in ima.h above in the patch, and
re-defined here?
> +unsigned long iint_flags(struct integrity_iint_cache *iint,
> + struct ns_status *status)
> +{
> + if (!status)
> + return iint->flags;
> +
> + return iint->flags & (status->flags & IMA_NS_STATUS_FLAGS);
Just to confirm, is there any situation where:
iint->flags & IMA_NS_STATUS_FLAGS != status->flags & IMA_NS_STATUS_FLAGS
? i.e. can this line just be:
return status->flags & IMA_NS_STATUS_FLAGS;
Tycho
> +}
> +
> +unsigned long set_iint_flags(struct integrity_iint_cache *iint,
> + struct ns_status *status, unsigned long flags)
> +{
> + iint->flags = flags;
> + if (status)
> + status->flags = flags & IMA_NS_STATUS_FLAGS;
> + return flags;
> +}
> --
> 2.9.4
>
|
|
From: Mehmet K. <mka...@li...> - 2017-08-01 17:21:38
|
> On Aug 1, 2017, at 1:17 PM, Tycho Andersen <ty...@do...> wrote:
>
> Hi Mehmet,
>
> On Thu, Jul 20, 2017 at 06:50:31PM -0400, Mehmet Kayaalp wrote:
>> --- a/security/integrity/ima/ima_ns.c
>> +++ b/security/integrity/ima/ima_ns.c
>> @@ -301,3 +301,24 @@ struct ns_status *ima_get_ns_status(struct ima_namespace *ns,
>>
>> return status;
>> }
>> +
>> +#define IMA_NS_STATUS_ACTIONS IMA_AUDIT
>> +#define IMA_NS_STATUS_FLAGS IMA_AUDITED
>> +
>
> Seems like these are defined in ima.h above in the patch, and
> re-defined here?
Yes, it should be in the ima.h only.
>> +unsigned long iint_flags(struct integrity_iint_cache *iint,
>> + struct ns_status *status)
>> +{
>> + if (!status)
>> + return iint->flags;
>> +
>> + return iint->flags & (status->flags & IMA_NS_STATUS_FLAGS);
>
> Just to confirm, is there any situation where:
>
> iint->flags & IMA_NS_STATUS_FLAGS != status->flags & IMA_NS_STATUS_FLAGS
>
> ? i.e. can this line just be:
>
> return status->flags & IMA_NS_STATUS_FLAGS;
>
As Guilherme had pointed out, the first & should be |.
Mehmet
|
|
From: Mimi Z. <zo...@li...> - 2017-08-01 15:38:49
|
On Tue, 2017-08-01 at 12:42 +0200, Jan Kara wrote:
> On Mon 31-07-17 15:08:53, Mimi Zohar wrote:
> > On Mon, 2017-07-31 at 09:01 +0200, Jan Kara wrote:
> > > On Wed 26-07-17 09:22:52, Mimi Zohar wrote:
> > > > From: Christoph Hellwig <hc...@ls...>
> > > >
> > > > Add a new ->integrity_read file operation to read data for integrity
> > > > hash collection. This is defined to be equivalent to ->read_iter,
> > > > except that it will be called with the i_rwsem held exclusively.
> > >
> > > The patch looks mostly good to me.
> >
> > Thanks! Can I include your Ack-by?
>
> After gfs2 & ocfs2 matters are settled...
>
> >
> > > Just one question: How did you select
> > > filesystems that implement .integrity_read method?
> >
> > Initially I started out looking at the fs/.../Kconfig, but after
> > spending a while looking at the number of filesystems, I gave up and
> > asked Christoph (offline) where to begin. I also compared the
> > measurement list from before and after the change and noticed some
> > missing file measurements (eg. ramfs, shmem, efivarfs).
>
> OK, makes sense.
>
> > > And I still maintain
> > > that it would be IMHO safer to not pretend we support IMA on gfs2 and ocfs2
> > > unless you either make sure they are mounted in local-only mode or figure
> > > out how to deal with proper cluster locking.
> >
> > Agreed. With patch 1/7 "ima: always measure and audit files in
> > policy", at least a file measurement containing a 0x00's hash value
> > will be included in the IMA measurement list.
>
> Well, but for OCFS2 and GFS2 you have defined .integrity_read methods to
> generic_file_read_iter() and they will return data so IMA will think
> everything is fine. Just they may crash while doing so or return bogus data
> due to insufficient locking generic_file_read_iter() provides. So my
> suggestion is to just not provide .integrity_read for these two filesystems
> until you (or someone else) can figure out how to do that safely.
Sorry my explanation above wasn't clear. Yes, I'll remove the
integrity_read method definitions for gfs2 and ocfs2. As a result of
removing the integrity_read operation, the measurement list will
contain 0x00 hash values, instead of the real file hash.
Mimi
>
> > > > Signed-off-by: Christoph Hellwig <hc...@ls...>
> > > > Cc: Matthew Garrett <mat...@ne...>
> > > > Cc: Jan Kara <ja...@su...>
> > > > Cc: "Theodore Ts'o" <ty...@mi...>
> > > > Cc: Andreas Dilger <adi...@di...>
> > > > Cc: Jaegeuk Kim <ja...@ke...>
> > > > Cc: Chao Yu <yu...@hu...>
> > > > Cc: Steven Whitehouse <swh...@re...>
> > > > Cc: Bob Peterson <rpe...@re...>
> > > > Cc: David Woodhouse <dw...@in...>
> > > > Cc: Dave Kleikamp <sh...@ke...>
> > > > Cc: Ryusuke Konishi <kon...@la...>
> > > > Cc: Mark Fasheh <mf...@ve...>
> > > > Cc: Joel Becker <jl...@ev...>
> > > > Cc: Richard Weinberger <ri...@no...>
> > > > Cc: "Darrick J. Wong" <dar...@or...>
> > > > Cc: Hugh Dickins <hu...@go...>
> > > > Cc: Chris Mason <cl...@fb...>
> > > > Signed-off-by: Mimi Zohar <zo...@li...>
> > > >
> > > > Changelog v4:
> > > > - define ext2/4 specific ->integrity_read functions.
> > > > - properly fail file open with O_DIRECT on filesystem not mounted
> > > > with "-o dax".
> > > >
> > > > ---
> > > > Changelog v3:
> > > > - define simple_read_iter_from_buffer
> > > > - replace the existing efivarfs ->read method with ->read_iter method.
> > > > - squashed other fs definitions of ->integrity_read with this patch.
> > > >
> > > > Changelog v2:
> > > > - change iovec to kvec
> > > >
> > > > Changelog v1:
> > > > - update the patch description, removing the concept that the presence of
> > > > ->integrity_read indicates that the file system can support IMA. (Mimi)
> > > >
> > > > fs/btrfs/file.c | 1 +
> > > > fs/efivarfs/file.c | 12 +++++++-----
> > > > fs/ext2/file.c | 17 +++++++++++++++++
> > > > fs/ext4/file.c | 23 +++++++++++++++++++++++
> > > > fs/f2fs/file.c | 1 +
> > > > fs/gfs2/file.c | 2 ++
> > > > fs/jffs2/file.c | 1 +
> > > > fs/jfs/file.c | 1 +
> > > > fs/libfs.c | 32 ++++++++++++++++++++++++++++++++
> > > > fs/nilfs2/file.c | 1 +
> > > > fs/ocfs2/file.c | 1 +
> > > > fs/ramfs/file-mmu.c | 1 +
> > > > fs/ramfs/file-nommu.c | 1 +
> > > > fs/ubifs/file.c | 1 +
> > > > fs/xfs/xfs_file.c | 21 +++++++++++++++++++++
> > > > include/linux/fs.h | 3 +++
> > > > mm/shmem.c | 1 +
> > > > security/integrity/iint.c | 20 ++++++++++++++------
> > > > 18 files changed, 129 insertions(+), 11 deletions(-)
> > > >
> > > > diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> > > > index 9e75d8a39aac..2542dc66c85c 100644
> > > > --- a/fs/btrfs/file.c
> > > > +++ b/fs/btrfs/file.c
> > > > @@ -3125,6 +3125,7 @@ const struct file_operations btrfs_file_operations = {
> > > > #endif
> > > > .clone_file_range = btrfs_clone_file_range,
> > > > .dedupe_file_range = btrfs_dedupe_file_range,
> > > > + .integrity_read = generic_file_read_iter,
> > > > };
> > > >
> > > > void btrfs_auto_defrag_exit(void)
> > > > diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c
> > > > index 5f22e74bbade..17955a92a5b3 100644
> > > > --- a/fs/efivarfs/file.c
> > > > +++ b/fs/efivarfs/file.c
> > > > @@ -64,9 +64,10 @@ static ssize_t efivarfs_file_write(struct file *file,
> > > > return bytes;
> > > > }
> > > >
> > > > -static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
> > > > - size_t count, loff_t *ppos)
> > > > +static ssize_t efivarfs_file_read_iter(struct kiocb *iocb,
> > > > + struct iov_iter *iter)
> > > > {
> > > > + struct file *file = iocb->ki_filp;
> > > > struct efivar_entry *var = file->private_data;
> > > > unsigned long datasize = 0;
> > > > u32 attributes;
> > > > @@ -96,8 +97,8 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
> > > > goto out_free;
> > > >
> > > > memcpy(data, &attributes, sizeof(attributes));
> > > > - size = simple_read_from_buffer(userbuf, count, ppos,
> > > > - data, datasize + sizeof(attributes));
> > > > + size = simple_read_iter_from_buffer(iocb, iter, data,
> > > > + datasize + sizeof(attributes));
> > > > out_free:
> > > > kfree(data);
> > > >
> > > > @@ -174,8 +175,9 @@ efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p)
> > > >
> > > > const struct file_operations efivarfs_file_operations = {
> > > > .open = simple_open,
> > > > - .read = efivarfs_file_read,
> > > > + .read_iter = efivarfs_file_read_iter,
> > > > .write = efivarfs_file_write,
> > > > .llseek = no_llseek,
> > > > .unlocked_ioctl = efivarfs_file_ioctl,
> > > > + .integrity_read = efivarfs_file_read_iter,
> > > > };
> > > > diff --git a/fs/ext2/file.c b/fs/ext2/file.c
> > > > index d34d32bdc944..111069de1973 100644
> > > > --- a/fs/ext2/file.c
> > > > +++ b/fs/ext2/file.c
> > > > @@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> > > > return generic_file_read_iter(iocb, to);
> > > > }
> > > >
> > > > +static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
> > > > + struct iov_iter *to)
> > > > +{
> > > > + struct inode *inode = file_inode(iocb->ki_filp);
> > > > +
> > > > + lockdep_assert_held(&inode->i_rwsem);
> > > > +#ifdef CONFIG_FS_DAX
> > > > + if (!iov_iter_count(to))
> > > > + return 0; /* skip atime */
> > > > +
> > > > + if (IS_DAX(iocb->ki_filp->f_mapping->host))
> > > > + return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
> > > > +#endif
> > > > + return generic_file_read_iter(iocb, to);
> > > > +}
> > > > +
> > > > static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
> > > > {
> > > > #ifdef CONFIG_FS_DAX
> > > > @@ -216,6 +232,7 @@ const struct file_operations ext2_file_operations = {
> > > > .get_unmapped_area = thp_get_unmapped_area,
> > > > .splice_read = generic_file_splice_read,
> > > > .splice_write = iter_file_splice_write,
> > > > + .integrity_read = ext2_file_integrity_read_iter,
> > > > };
> > > >
> > > > const struct inode_operations ext2_file_inode_operations = {
> > > > diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> > > > index 58294c9a7e1d..cb423fff935f 100644
> > > > --- a/fs/ext4/file.c
> > > > +++ b/fs/ext4/file.c
> > > > @@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> > > > return generic_file_read_iter(iocb, to);
> > > > }
> > > >
> > > > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > > > + struct iov_iter *to)
> > > > +{
> > > > + struct inode *inode = file_inode(iocb->ki_filp);
> > > > + int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > > > +
> > > > + lockdep_assert_held(&inode->i_rwsem);
> > > > + if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > > > + return -EIO;
> > > > +
> > > > + if (!iov_iter_count(to))
> > > > + return 0; /* skip atime */
> > > > +
> > > > +#ifdef CONFIG_FS_DAX
> > > > + if (IS_DAX(inode))
> > > > + return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > > > +#endif
> > > > + if (o_direct)
> > > > + return -EINVAL;
> > > > + return generic_file_read_iter(iocb, to);
> > > > +}
> > > > +
> > > > /*
> > > > * Called when an inode is released. Note that this is different
> > > > * from ext4_file_open: open gets called at every open, but release
> > > > @@ -747,6 +769,7 @@ const struct file_operations ext4_file_operations = {
> > > > .splice_read = generic_file_splice_read,
> > > > .splice_write = iter_file_splice_write,
> > > > .fallocate = ext4_fallocate,
> > > > + .integrity_read = ext4_file_integrity_read_iter,
> > > > };
> > > >
> > > > const struct inode_operations ext4_file_inode_operations = {
> > > > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> > > > index 2706130c261b..82ea81da0b2d 100644
> > > > --- a/fs/f2fs/file.c
> > > > +++ b/fs/f2fs/file.c
> > > > @@ -2514,4 +2514,5 @@ const struct file_operations f2fs_file_operations = {
> > > > #endif
> > > > .splice_read = generic_file_splice_read,
> > > > .splice_write = iter_file_splice_write,
> > > > + .integrity_read = generic_file_read_iter,
> > > > };
> > > > diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
> > > > index c2062a108d19..9b49d09ba180 100644
> > > > --- a/fs/gfs2/file.c
> > > > +++ b/fs/gfs2/file.c
> > > > @@ -1124,6 +1124,7 @@ const struct file_operations gfs2_file_fops = {
> > > > .splice_write = gfs2_file_splice_write,
> > > > .setlease = simple_nosetlease,
> > > > .fallocate = gfs2_fallocate,
> > > > + .integrity_read = generic_file_read_iter,
> > > > };
> > > >
> > > > const struct file_operations gfs2_dir_fops = {
> > > > @@ -1152,6 +1153,7 @@ const struct file_operations gfs2_file_fops_nolock = {
> > > > .splice_write = gfs2_file_splice_write,
> > > > .setlease = generic_setlease,
> > > > .fallocate = gfs2_fallocate,
> > > > + .integrity_read = generic_file_read_iter,
> > > > };
> > > >
> > > > const struct file_operations gfs2_dir_fops_nolock = {
> > > > diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
> > > > index c12476e309c6..5a63034cccf5 100644
> > > > --- a/fs/jffs2/file.c
> > > > +++ b/fs/jffs2/file.c
> > > > @@ -57,6 +57,7 @@ const struct file_operations jffs2_file_operations =
> > > > .mmap = generic_file_readonly_mmap,
> > > > .fsync = jffs2_fsync,
> > > > .splice_read = generic_file_splice_read,
> > > > + .integrity_read = generic_file_read_iter,
> > > > };
> > > >
> > > > /* jffs2_file_inode_operations */
> > > > diff --git a/fs/jfs/file.c b/fs/jfs/file.c
> > > > index 739492c7a3fd..423512a810e4 100644
> > > > --- a/fs/jfs/file.c
> > > > +++ b/fs/jfs/file.c
> > > > @@ -162,4 +162,5 @@ const struct file_operations jfs_file_operations = {
> > > > #ifdef CONFIG_COMPAT
> > > > .compat_ioctl = jfs_compat_ioctl,
> > > > #endif
> > > > + .integrity_read = generic_file_read_iter,
> > > > };
> > > > diff --git a/fs/libfs.c b/fs/libfs.c
> > > > index 3aabe553fc45..99333264a0a7 100644
> > > > --- a/fs/libfs.c
> > > > +++ b/fs/libfs.c
> > > > @@ -16,6 +16,7 @@
> > > > #include <linux/exportfs.h>
> > > > #include <linux/writeback.h>
> > > > #include <linux/buffer_head.h> /* sync_mapping_buffers */
> > > > +#include <linux/uio.h>
> > > >
> > > > #include <linux/uaccess.h>
> > > >
> > > > @@ -676,6 +677,37 @@ ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
> > > > EXPORT_SYMBOL(simple_write_to_buffer);
> > > >
> > > > /**
> > > > + * simple_read_iter_from_buffer - copy data from the buffer to user space
> > > > + * @iocb: struct containing the file, the current position and other info
> > > > + * @to: the user space buffer to read to
> > > > + * @from: the buffer to read from
> > > > + * @available: the size of the buffer
> > > > + *
> > > > + * The simple_read_iter_from_buffer() function reads up to @available bytes
> > > > + * from the current buffer into the user space buffer.
> > > > + *
> > > > + * On success, the current buffer offset is advanced by the number of bytes
> > > > + * read, or a negative value is returned on error.
> > > > + **/
> > > > +ssize_t simple_read_iter_from_buffer(struct kiocb *iocb, struct iov_iter *to,
> > > > + const void *from, size_t available)
> > > > +{
> > > > + loff_t pos = iocb->ki_pos;
> > > > + size_t ret;
> > > > +
> > > > + if (pos < 0)
> > > > + return -EINVAL;
> > > > + if (pos >= available)
> > > > + return 0;
> > > > + ret = copy_to_iter(from + pos, available - pos, to);
> > > > + if (!ret && iov_iter_count(to))
> > > > + return -EFAULT;
> > > > + iocb->ki_pos = pos + ret;
> > > > + return ret;
> > > > +}
> > > > +EXPORT_SYMBOL(simple_read_iter_from_buffer);
> > > > +
> > > > +/**
> > > > * memory_read_from_buffer - copy data from the buffer
> > > > * @to: the kernel space buffer to read to
> > > > * @count: the maximum number of bytes to read
> > > > diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c
> > > > index c5fa3dee72fc..55e058ac487f 100644
> > > > --- a/fs/nilfs2/file.c
> > > > +++ b/fs/nilfs2/file.c
> > > > @@ -150,6 +150,7 @@ const struct file_operations nilfs_file_operations = {
> > > > /* .release = nilfs_release_file, */
> > > > .fsync = nilfs_sync_file,
> > > > .splice_read = generic_file_splice_read,
> > > > + .integrity_read = generic_file_read_iter,
> > > > };
> > > >
> > > > const struct inode_operations nilfs_file_inode_operations = {
> > > > diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
> > > > index bfeb647459d9..2832a7c92acd 100644
> > > > --- a/fs/ocfs2/file.c
> > > > +++ b/fs/ocfs2/file.c
> > > > @@ -2536,6 +2536,7 @@ const struct file_operations ocfs2_fops = {
> > > > .fallocate = ocfs2_fallocate,
> > > > .clone_file_range = ocfs2_file_clone_range,
> > > > .dedupe_file_range = ocfs2_file_dedupe_range,
> > > > + .integrity_read = ocfs2_file_read_iter,
> > > > };
> > > >
> > > > const struct file_operations ocfs2_dops = {
> > > > diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c
> > > > index 12af0490322f..4f24d1b589b1 100644
> > > > --- a/fs/ramfs/file-mmu.c
> > > > +++ b/fs/ramfs/file-mmu.c
> > > > @@ -47,6 +47,7 @@ const struct file_operations ramfs_file_operations = {
> > > > .splice_write = iter_file_splice_write,
> > > > .llseek = generic_file_llseek,
> > > > .get_unmapped_area = ramfs_mmu_get_unmapped_area,
> > > > + .integrity_read = generic_file_read_iter,
> > > > };
> > > >
> > > > const struct inode_operations ramfs_file_inode_operations = {
> > > > diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
> > > > index 2ef7ce75c062..5ee704fa84e0 100644
> > > > --- a/fs/ramfs/file-nommu.c
> > > > +++ b/fs/ramfs/file-nommu.c
> > > > @@ -50,6 +50,7 @@ const struct file_operations ramfs_file_operations = {
> > > > .splice_read = generic_file_splice_read,
> > > > .splice_write = iter_file_splice_write,
> > > > .llseek = generic_file_llseek,
> > > > + .integrity_read = generic_file_read_iter,
> > > > };
> > > >
> > > > const struct inode_operations ramfs_file_inode_operations = {
> > > > diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
> > > > index 8cad0b19b404..5e52a315e18b 100644
> > > > --- a/fs/ubifs/file.c
> > > > +++ b/fs/ubifs/file.c
> > > > @@ -1747,4 +1747,5 @@ const struct file_operations ubifs_file_operations = {
> > > > #ifdef CONFIG_COMPAT
> > > > .compat_ioctl = ubifs_compat_ioctl,
> > > > #endif
> > > > + .integrity_read = generic_file_read_iter,
> > > > };
> > > > diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> > > > index c4893e226fd8..0a6704b563d6 100644
> > > > --- a/fs/xfs/xfs_file.c
> > > > +++ b/fs/xfs/xfs_file.c
> > > > @@ -292,6 +292,26 @@ xfs_file_read_iter(
> > > > return ret;
> > > > }
> > > >
> > > > +static ssize_t
> > > > +xfs_integrity_read(
> > > > + struct kiocb *iocb,
> > > > + struct iov_iter *to)
> > > > +{
> > > > + struct inode *inode = file_inode(iocb->ki_filp);
> > > > + struct xfs_mount *mp = XFS_I(inode)->i_mount;
> > > > +
> > > > + lockdep_assert_held(&inode->i_rwsem);
> > > > +
> > > > + XFS_STATS_INC(mp, xs_read_calls);
> > > > +
> > > > + if (XFS_FORCED_SHUTDOWN(mp))
> > > > + return -EIO;
> > > > +
> > > > + if (IS_DAX(inode))
> > > > + return dax_iomap_rw(iocb, to, &xfs_iomap_ops);
> > > > + return generic_file_read_iter(iocb, to);
> > > > +}
> > > > +
> > > > /*
> > > > * Zero any on disk space between the current EOF and the new, larger EOF.
> > > > *
> > > > @@ -1175,6 +1195,7 @@ const struct file_operations xfs_file_operations = {
> > > > .fallocate = xfs_file_fallocate,
> > > > .clone_file_range = xfs_file_clone_range,
> > > > .dedupe_file_range = xfs_file_dedupe_range,
> > > > + .integrity_read = xfs_integrity_read,
> > > > };
> > > >
> > > > const struct file_operations xfs_dir_file_operations = {
> > > > diff --git a/include/linux/fs.h b/include/linux/fs.h
> > > > index 6e1fd5d21248..8d0d10e1dd93 100644
> > > > --- a/include/linux/fs.h
> > > > +++ b/include/linux/fs.h
> > > > @@ -1699,6 +1699,7 @@ struct file_operations {
> > > > u64);
> > > > ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
> > > > u64);
> > > > + ssize_t (*integrity_read)(struct kiocb *, struct iov_iter *);
> > > > } __randomize_layout;
> > > >
> > > > struct inode_operations {
> > > > @@ -3097,6 +3098,8 @@ extern void simple_release_fs(struct vfsmount **mount, int *count);
> > > >
> > > > extern ssize_t simple_read_from_buffer(void __user *to, size_t count,
> > > > loff_t *ppos, const void *from, size_t available);
> > > > +extern ssize_t simple_read_iter_from_buffer(struct kiocb *iocb,
> > > > + struct iov_iter *to, const void *from, size_t available);
> > > > extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
> > > > const void __user *from, size_t count);
> > > >
> > > > diff --git a/mm/shmem.c b/mm/shmem.c
> > > > index b0aa6075d164..805d99011ca4 100644
> > > > --- a/mm/shmem.c
> > > > +++ b/mm/shmem.c
> > > > @@ -3849,6 +3849,7 @@ static const struct file_operations shmem_file_operations = {
> > > > .splice_read = generic_file_splice_read,
> > > > .splice_write = iter_file_splice_write,
> > > > .fallocate = shmem_fallocate,
> > > > + .integrity_read = shmem_file_read_iter,
> > > > #endif
> > > > };
> > > >
> > > > diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> > > > index 6fc888ca468e..df04f35a1d40 100644
> > > > --- a/security/integrity/iint.c
> > > > +++ b/security/integrity/iint.c
> > > > @@ -21,6 +21,7 @@
> > > > #include <linux/rbtree.h>
> > > > #include <linux/file.h>
> > > > #include <linux/uaccess.h>
> > > > +#include <linux/uio.h>
> > > > #include "integrity.h"
> > > >
> > > > static struct rb_root integrity_iint_tree = RB_ROOT;
> > > > @@ -184,18 +185,25 @@ security_initcall(integrity_iintcache_init);
> > > > int integrity_kernel_read(struct file *file, loff_t offset,
> > > > void *addr, unsigned long count)
> > > > {
> > > > - mm_segment_t old_fs;
> > > > - char __user *buf = (char __user *)addr;
> > > > + struct inode *inode = file_inode(file);
> > > > + struct kvec iov = { .iov_base = addr, .iov_len = count };
> > > > + struct kiocb kiocb;
> > > > + struct iov_iter iter;
> > > > ssize_t ret;
> > > >
> > > > + lockdep_assert_held(&inode->i_rwsem);
> > > > +
> > > > if (!(file->f_mode & FMODE_READ))
> > > > return -EBADF;
> > > > + if (!file->f_op->integrity_read)
> > > > + return -EBADF;
> > > >
> > > > - old_fs = get_fs();
> > > > - set_fs(get_ds());
> > > > - ret = __vfs_read(file, buf, count, &offset);
> > > > - set_fs(old_fs);
> > > > + init_sync_kiocb(&kiocb, file);
> > > > + kiocb.ki_pos = offset;
> > > > + iov_iter_kvec(&iter, READ | ITER_KVEC, &iov, 1, count);
> > > >
> > > > + ret = file->f_op->integrity_read(&kiocb, &iter);
> > > > + BUG_ON(ret == -EIOCBQUEUED);
> > > > return ret;
> > > > }
> > > >
> > > > --
> > > > 2.7.4
> > > >
> > > >
> >
|
|
From: Roberto S. <rob...@hu...> - 2017-08-01 10:59:03
|
On 8/1/2017 12:27 PM, Christoph Hellwig wrote: > On Tue, Aug 01, 2017 at 12:20:36PM +0200, Roberto Sassu wrote: >> This patch introduces a parser for RPM packages. It extracts the digests >> from the RPMTAG_FILEDIGESTS header section and converts them to binary data >> before adding them to the hash table. >> >> The advantage of this data type is that verifiers can determine who >> produced that data, as headers are signed by Linux distributions vendors. >> RPM headers signatures can be provided as digest list metadata. > > Err, parsing arbitrary file formats has no business in the kernel. The benefit of this choice is that no actions are required for Linux distribution vendors to support the solution I'm proposing, because they already provide signed digest lists (RPM headers). Since the proof of loading a digest list is the digest of the digest list (included in the list metadata), if RPM headers are converted to a different format, remote attestation verifiers cannot check the signature. If the concern is security, it would be possible to prevent unsigned RPM headers from being parsed, if the PGP key type is upstreamed (adding in CC key...@vg...). Roberto -- HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063 Managing Director: Bo PENG, Qiuen PENG, Shengli WANG |
|
From: Jan K. <ja...@su...> - 2017-08-01 10:43:04
|
On Mon 31-07-17 15:08:53, Mimi Zohar wrote:
> On Mon, 2017-07-31 at 09:01 +0200, Jan Kara wrote:
> > On Wed 26-07-17 09:22:52, Mimi Zohar wrote:
> > > From: Christoph Hellwig <hc...@ls...>
> > >
> > > Add a new ->integrity_read file operation to read data for integrity
> > > hash collection. This is defined to be equivalent to ->read_iter,
> > > except that it will be called with the i_rwsem held exclusively.
> >
> > The patch looks mostly good to me.
>
> Thanks! Can I include your Ack-by?
After gfs2 & ocfs2 matters are settled...
>
> > Just one question: How did you select
> > filesystems that implement .integrity_read method?
>
> Initially I started out looking at the fs/.../Kconfig, but after
> spending a while looking at the number of filesystems, I gave up and
> asked Christoph (offline) where to begin. I also compared the
> measurement list from before and after the change and noticed some
> missing file measurements (eg. ramfs, shmem, efivarfs).
OK, makes sense.
> > And I still maintain
> > that it would be IMHO safer to not pretend we support IMA on gfs2 and ocfs2
> > unless you either make sure they are mounted in local-only mode or figure
> > out how to deal with proper cluster locking.
>
> Agreed. With patch 1/7 "ima: always measure and audit files in
> policy", at least a file measurement containing a 0x00's hash value
> will be included in the IMA measurement list.
Well, but for OCFS2 and GFS2 you have defined .integrity_read methods to
generic_file_read_iter() and they will return data so IMA will think
everything is fine. Just they may crash while doing so or return bogus data
due to insufficient locking generic_file_read_iter() provides. So my
suggestion is to just not provide .integrity_read for these two filesystems
until you (or someone else) can figure out how to do that safely.
Honza
> > > Signed-off-by: Christoph Hellwig <hc...@ls...>
> > > Cc: Matthew Garrett <mat...@ne...>
> > > Cc: Jan Kara <ja...@su...>
> > > Cc: "Theodore Ts'o" <ty...@mi...>
> > > Cc: Andreas Dilger <adi...@di...>
> > > Cc: Jaegeuk Kim <ja...@ke...>
> > > Cc: Chao Yu <yu...@hu...>
> > > Cc: Steven Whitehouse <swh...@re...>
> > > Cc: Bob Peterson <rpe...@re...>
> > > Cc: David Woodhouse <dw...@in...>
> > > Cc: Dave Kleikamp <sh...@ke...>
> > > Cc: Ryusuke Konishi <kon...@la...>
> > > Cc: Mark Fasheh <mf...@ve...>
> > > Cc: Joel Becker <jl...@ev...>
> > > Cc: Richard Weinberger <ri...@no...>
> > > Cc: "Darrick J. Wong" <dar...@or...>
> > > Cc: Hugh Dickins <hu...@go...>
> > > Cc: Chris Mason <cl...@fb...>
> > > Signed-off-by: Mimi Zohar <zo...@li...>
> > >
> > > Changelog v4:
> > > - define ext2/4 specific ->integrity_read functions.
> > > - properly fail file open with O_DIRECT on filesystem not mounted
> > > with "-o dax".
> > >
> > > ---
> > > Changelog v3:
> > > - define simple_read_iter_from_buffer
> > > - replace the existing efivarfs ->read method with ->read_iter method.
> > > - squashed other fs definitions of ->integrity_read with this patch.
> > >
> > > Changelog v2:
> > > - change iovec to kvec
> > >
> > > Changelog v1:
> > > - update the patch description, removing the concept that the presence of
> > > ->integrity_read indicates that the file system can support IMA. (Mimi)
> > >
> > > fs/btrfs/file.c | 1 +
> > > fs/efivarfs/file.c | 12 +++++++-----
> > > fs/ext2/file.c | 17 +++++++++++++++++
> > > fs/ext4/file.c | 23 +++++++++++++++++++++++
> > > fs/f2fs/file.c | 1 +
> > > fs/gfs2/file.c | 2 ++
> > > fs/jffs2/file.c | 1 +
> > > fs/jfs/file.c | 1 +
> > > fs/libfs.c | 32 ++++++++++++++++++++++++++++++++
> > > fs/nilfs2/file.c | 1 +
> > > fs/ocfs2/file.c | 1 +
> > > fs/ramfs/file-mmu.c | 1 +
> > > fs/ramfs/file-nommu.c | 1 +
> > > fs/ubifs/file.c | 1 +
> > > fs/xfs/xfs_file.c | 21 +++++++++++++++++++++
> > > include/linux/fs.h | 3 +++
> > > mm/shmem.c | 1 +
> > > security/integrity/iint.c | 20 ++++++++++++++------
> > > 18 files changed, 129 insertions(+), 11 deletions(-)
> > >
> > > diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> > > index 9e75d8a39aac..2542dc66c85c 100644
> > > --- a/fs/btrfs/file.c
> > > +++ b/fs/btrfs/file.c
> > > @@ -3125,6 +3125,7 @@ const struct file_operations btrfs_file_operations = {
> > > #endif
> > > .clone_file_range = btrfs_clone_file_range,
> > > .dedupe_file_range = btrfs_dedupe_file_range,
> > > + .integrity_read = generic_file_read_iter,
> > > };
> > >
> > > void btrfs_auto_defrag_exit(void)
> > > diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c
> > > index 5f22e74bbade..17955a92a5b3 100644
> > > --- a/fs/efivarfs/file.c
> > > +++ b/fs/efivarfs/file.c
> > > @@ -64,9 +64,10 @@ static ssize_t efivarfs_file_write(struct file *file,
> > > return bytes;
> > > }
> > >
> > > -static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
> > > - size_t count, loff_t *ppos)
> > > +static ssize_t efivarfs_file_read_iter(struct kiocb *iocb,
> > > + struct iov_iter *iter)
> > > {
> > > + struct file *file = iocb->ki_filp;
> > > struct efivar_entry *var = file->private_data;
> > > unsigned long datasize = 0;
> > > u32 attributes;
> > > @@ -96,8 +97,8 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
> > > goto out_free;
> > >
> > > memcpy(data, &attributes, sizeof(attributes));
> > > - size = simple_read_from_buffer(userbuf, count, ppos,
> > > - data, datasize + sizeof(attributes));
> > > + size = simple_read_iter_from_buffer(iocb, iter, data,
> > > + datasize + sizeof(attributes));
> > > out_free:
> > > kfree(data);
> > >
> > > @@ -174,8 +175,9 @@ efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p)
> > >
> > > const struct file_operations efivarfs_file_operations = {
> > > .open = simple_open,
> > > - .read = efivarfs_file_read,
> > > + .read_iter = efivarfs_file_read_iter,
> > > .write = efivarfs_file_write,
> > > .llseek = no_llseek,
> > > .unlocked_ioctl = efivarfs_file_ioctl,
> > > + .integrity_read = efivarfs_file_read_iter,
> > > };
> > > diff --git a/fs/ext2/file.c b/fs/ext2/file.c
> > > index d34d32bdc944..111069de1973 100644
> > > --- a/fs/ext2/file.c
> > > +++ b/fs/ext2/file.c
> > > @@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> > > return generic_file_read_iter(iocb, to);
> > > }
> > >
> > > +static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
> > > + struct iov_iter *to)
> > > +{
> > > + struct inode *inode = file_inode(iocb->ki_filp);
> > > +
> > > + lockdep_assert_held(&inode->i_rwsem);
> > > +#ifdef CONFIG_FS_DAX
> > > + if (!iov_iter_count(to))
> > > + return 0; /* skip atime */
> > > +
> > > + if (IS_DAX(iocb->ki_filp->f_mapping->host))
> > > + return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
> > > +#endif
> > > + return generic_file_read_iter(iocb, to);
> > > +}
> > > +
> > > static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
> > > {
> > > #ifdef CONFIG_FS_DAX
> > > @@ -216,6 +232,7 @@ const struct file_operations ext2_file_operations = {
> > > .get_unmapped_area = thp_get_unmapped_area,
> > > .splice_read = generic_file_splice_read,
> > > .splice_write = iter_file_splice_write,
> > > + .integrity_read = ext2_file_integrity_read_iter,
> > > };
> > >
> > > const struct inode_operations ext2_file_inode_operations = {
> > > diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> > > index 58294c9a7e1d..cb423fff935f 100644
> > > --- a/fs/ext4/file.c
> > > +++ b/fs/ext4/file.c
> > > @@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> > > return generic_file_read_iter(iocb, to);
> > > }
> > >
> > > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > > + struct iov_iter *to)
> > > +{
> > > + struct inode *inode = file_inode(iocb->ki_filp);
> > > + int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > > +
> > > + lockdep_assert_held(&inode->i_rwsem);
> > > + if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > > + return -EIO;
> > > +
> > > + if (!iov_iter_count(to))
> > > + return 0; /* skip atime */
> > > +
> > > +#ifdef CONFIG_FS_DAX
> > > + if (IS_DAX(inode))
> > > + return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > > +#endif
> > > + if (o_direct)
> > > + return -EINVAL;
> > > + return generic_file_read_iter(iocb, to);
> > > +}
> > > +
> > > /*
> > > * Called when an inode is released. Note that this is different
> > > * from ext4_file_open: open gets called at every open, but release
> > > @@ -747,6 +769,7 @@ const struct file_operations ext4_file_operations = {
> > > .splice_read = generic_file_splice_read,
> > > .splice_write = iter_file_splice_write,
> > > .fallocate = ext4_fallocate,
> > > + .integrity_read = ext4_file_integrity_read_iter,
> > > };
> > >
> > > const struct inode_operations ext4_file_inode_operations = {
> > > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> > > index 2706130c261b..82ea81da0b2d 100644
> > > --- a/fs/f2fs/file.c
> > > +++ b/fs/f2fs/file.c
> > > @@ -2514,4 +2514,5 @@ const struct file_operations f2fs_file_operations = {
> > > #endif
> > > .splice_read = generic_file_splice_read,
> > > .splice_write = iter_file_splice_write,
> > > + .integrity_read = generic_file_read_iter,
> > > };
> > > diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
> > > index c2062a108d19..9b49d09ba180 100644
> > > --- a/fs/gfs2/file.c
> > > +++ b/fs/gfs2/file.c
> > > @@ -1124,6 +1124,7 @@ const struct file_operations gfs2_file_fops = {
> > > .splice_write = gfs2_file_splice_write,
> > > .setlease = simple_nosetlease,
> > > .fallocate = gfs2_fallocate,
> > > + .integrity_read = generic_file_read_iter,
> > > };
> > >
> > > const struct file_operations gfs2_dir_fops = {
> > > @@ -1152,6 +1153,7 @@ const struct file_operations gfs2_file_fops_nolock = {
> > > .splice_write = gfs2_file_splice_write,
> > > .setlease = generic_setlease,
> > > .fallocate = gfs2_fallocate,
> > > + .integrity_read = generic_file_read_iter,
> > > };
> > >
> > > const struct file_operations gfs2_dir_fops_nolock = {
> > > diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
> > > index c12476e309c6..5a63034cccf5 100644
> > > --- a/fs/jffs2/file.c
> > > +++ b/fs/jffs2/file.c
> > > @@ -57,6 +57,7 @@ const struct file_operations jffs2_file_operations =
> > > .mmap = generic_file_readonly_mmap,
> > > .fsync = jffs2_fsync,
> > > .splice_read = generic_file_splice_read,
> > > + .integrity_read = generic_file_read_iter,
> > > };
> > >
> > > /* jffs2_file_inode_operations */
> > > diff --git a/fs/jfs/file.c b/fs/jfs/file.c
> > > index 739492c7a3fd..423512a810e4 100644
> > > --- a/fs/jfs/file.c
> > > +++ b/fs/jfs/file.c
> > > @@ -162,4 +162,5 @@ const struct file_operations jfs_file_operations = {
> > > #ifdef CONFIG_COMPAT
> > > .compat_ioctl = jfs_compat_ioctl,
> > > #endif
> > > + .integrity_read = generic_file_read_iter,
> > > };
> > > diff --git a/fs/libfs.c b/fs/libfs.c
> > > index 3aabe553fc45..99333264a0a7 100644
> > > --- a/fs/libfs.c
> > > +++ b/fs/libfs.c
> > > @@ -16,6 +16,7 @@
> > > #include <linux/exportfs.h>
> > > #include <linux/writeback.h>
> > > #include <linux/buffer_head.h> /* sync_mapping_buffers */
> > > +#include <linux/uio.h>
> > >
> > > #include <linux/uaccess.h>
> > >
> > > @@ -676,6 +677,37 @@ ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
> > > EXPORT_SYMBOL(simple_write_to_buffer);
> > >
> > > /**
> > > + * simple_read_iter_from_buffer - copy data from the buffer to user space
> > > + * @iocb: struct containing the file, the current position and other info
> > > + * @to: the user space buffer to read to
> > > + * @from: the buffer to read from
> > > + * @available: the size of the buffer
> > > + *
> > > + * The simple_read_iter_from_buffer() function reads up to @available bytes
> > > + * from the current buffer into the user space buffer.
> > > + *
> > > + * On success, the current buffer offset is advanced by the number of bytes
> > > + * read, or a negative value is returned on error.
> > > + **/
> > > +ssize_t simple_read_iter_from_buffer(struct kiocb *iocb, struct iov_iter *to,
> > > + const void *from, size_t available)
> > > +{
> > > + loff_t pos = iocb->ki_pos;
> > > + size_t ret;
> > > +
> > > + if (pos < 0)
> > > + return -EINVAL;
> > > + if (pos >= available)
> > > + return 0;
> > > + ret = copy_to_iter(from + pos, available - pos, to);
> > > + if (!ret && iov_iter_count(to))
> > > + return -EFAULT;
> > > + iocb->ki_pos = pos + ret;
> > > + return ret;
> > > +}
> > > +EXPORT_SYMBOL(simple_read_iter_from_buffer);
> > > +
> > > +/**
> > > * memory_read_from_buffer - copy data from the buffer
> > > * @to: the kernel space buffer to read to
> > > * @count: the maximum number of bytes to read
> > > diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c
> > > index c5fa3dee72fc..55e058ac487f 100644
> > > --- a/fs/nilfs2/file.c
> > > +++ b/fs/nilfs2/file.c
> > > @@ -150,6 +150,7 @@ const struct file_operations nilfs_file_operations = {
> > > /* .release = nilfs_release_file, */
> > > .fsync = nilfs_sync_file,
> > > .splice_read = generic_file_splice_read,
> > > + .integrity_read = generic_file_read_iter,
> > > };
> > >
> > > const struct inode_operations nilfs_file_inode_operations = {
> > > diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
> > > index bfeb647459d9..2832a7c92acd 100644
> > > --- a/fs/ocfs2/file.c
> > > +++ b/fs/ocfs2/file.c
> > > @@ -2536,6 +2536,7 @@ const struct file_operations ocfs2_fops = {
> > > .fallocate = ocfs2_fallocate,
> > > .clone_file_range = ocfs2_file_clone_range,
> > > .dedupe_file_range = ocfs2_file_dedupe_range,
> > > + .integrity_read = ocfs2_file_read_iter,
> > > };
> > >
> > > const struct file_operations ocfs2_dops = {
> > > diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c
> > > index 12af0490322f..4f24d1b589b1 100644
> > > --- a/fs/ramfs/file-mmu.c
> > > +++ b/fs/ramfs/file-mmu.c
> > > @@ -47,6 +47,7 @@ const struct file_operations ramfs_file_operations = {
> > > .splice_write = iter_file_splice_write,
> > > .llseek = generic_file_llseek,
> > > .get_unmapped_area = ramfs_mmu_get_unmapped_area,
> > > + .integrity_read = generic_file_read_iter,
> > > };
> > >
> > > const struct inode_operations ramfs_file_inode_operations = {
> > > diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
> > > index 2ef7ce75c062..5ee704fa84e0 100644
> > > --- a/fs/ramfs/file-nommu.c
> > > +++ b/fs/ramfs/file-nommu.c
> > > @@ -50,6 +50,7 @@ const struct file_operations ramfs_file_operations = {
> > > .splice_read = generic_file_splice_read,
> > > .splice_write = iter_file_splice_write,
> > > .llseek = generic_file_llseek,
> > > + .integrity_read = generic_file_read_iter,
> > > };
> > >
> > > const struct inode_operations ramfs_file_inode_operations = {
> > > diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
> > > index 8cad0b19b404..5e52a315e18b 100644
> > > --- a/fs/ubifs/file.c
> > > +++ b/fs/ubifs/file.c
> > > @@ -1747,4 +1747,5 @@ const struct file_operations ubifs_file_operations = {
> > > #ifdef CONFIG_COMPAT
> > > .compat_ioctl = ubifs_compat_ioctl,
> > > #endif
> > > + .integrity_read = generic_file_read_iter,
> > > };
> > > diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> > > index c4893e226fd8..0a6704b563d6 100644
> > > --- a/fs/xfs/xfs_file.c
> > > +++ b/fs/xfs/xfs_file.c
> > > @@ -292,6 +292,26 @@ xfs_file_read_iter(
> > > return ret;
> > > }
> > >
> > > +static ssize_t
> > > +xfs_integrity_read(
> > > + struct kiocb *iocb,
> > > + struct iov_iter *to)
> > > +{
> > > + struct inode *inode = file_inode(iocb->ki_filp);
> > > + struct xfs_mount *mp = XFS_I(inode)->i_mount;
> > > +
> > > + lockdep_assert_held(&inode->i_rwsem);
> > > +
> > > + XFS_STATS_INC(mp, xs_read_calls);
> > > +
> > > + if (XFS_FORCED_SHUTDOWN(mp))
> > > + return -EIO;
> > > +
> > > + if (IS_DAX(inode))
> > > + return dax_iomap_rw(iocb, to, &xfs_iomap_ops);
> > > + return generic_file_read_iter(iocb, to);
> > > +}
> > > +
> > > /*
> > > * Zero any on disk space between the current EOF and the new, larger EOF.
> > > *
> > > @@ -1175,6 +1195,7 @@ const struct file_operations xfs_file_operations = {
> > > .fallocate = xfs_file_fallocate,
> > > .clone_file_range = xfs_file_clone_range,
> > > .dedupe_file_range = xfs_file_dedupe_range,
> > > + .integrity_read = xfs_integrity_read,
> > > };
> > >
> > > const struct file_operations xfs_dir_file_operations = {
> > > diff --git a/include/linux/fs.h b/include/linux/fs.h
> > > index 6e1fd5d21248..8d0d10e1dd93 100644
> > > --- a/include/linux/fs.h
> > > +++ b/include/linux/fs.h
> > > @@ -1699,6 +1699,7 @@ struct file_operations {
> > > u64);
> > > ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
> > > u64);
> > > + ssize_t (*integrity_read)(struct kiocb *, struct iov_iter *);
> > > } __randomize_layout;
> > >
> > > struct inode_operations {
> > > @@ -3097,6 +3098,8 @@ extern void simple_release_fs(struct vfsmount **mount, int *count);
> > >
> > > extern ssize_t simple_read_from_buffer(void __user *to, size_t count,
> > > loff_t *ppos, const void *from, size_t available);
> > > +extern ssize_t simple_read_iter_from_buffer(struct kiocb *iocb,
> > > + struct iov_iter *to, const void *from, size_t available);
> > > extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
> > > const void __user *from, size_t count);
> > >
> > > diff --git a/mm/shmem.c b/mm/shmem.c
> > > index b0aa6075d164..805d99011ca4 100644
> > > --- a/mm/shmem.c
> > > +++ b/mm/shmem.c
> > > @@ -3849,6 +3849,7 @@ static const struct file_operations shmem_file_operations = {
> > > .splice_read = generic_file_splice_read,
> > > .splice_write = iter_file_splice_write,
> > > .fallocate = shmem_fallocate,
> > > + .integrity_read = shmem_file_read_iter,
> > > #endif
> > > };
> > >
> > > diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> > > index 6fc888ca468e..df04f35a1d40 100644
> > > --- a/security/integrity/iint.c
> > > +++ b/security/integrity/iint.c
> > > @@ -21,6 +21,7 @@
> > > #include <linux/rbtree.h>
> > > #include <linux/file.h>
> > > #include <linux/uaccess.h>
> > > +#include <linux/uio.h>
> > > #include "integrity.h"
> > >
> > > static struct rb_root integrity_iint_tree = RB_ROOT;
> > > @@ -184,18 +185,25 @@ security_initcall(integrity_iintcache_init);
> > > int integrity_kernel_read(struct file *file, loff_t offset,
> > > void *addr, unsigned long count)
> > > {
> > > - mm_segment_t old_fs;
> > > - char __user *buf = (char __user *)addr;
> > > + struct inode *inode = file_inode(file);
> > > + struct kvec iov = { .iov_base = addr, .iov_len = count };
> > > + struct kiocb kiocb;
> > > + struct iov_iter iter;
> > > ssize_t ret;
> > >
> > > + lockdep_assert_held(&inode->i_rwsem);
> > > +
> > > if (!(file->f_mode & FMODE_READ))
> > > return -EBADF;
> > > + if (!file->f_op->integrity_read)
> > > + return -EBADF;
> > >
> > > - old_fs = get_fs();
> > > - set_fs(get_ds());
> > > - ret = __vfs_read(file, buf, count, &offset);
> > > - set_fs(old_fs);
> > > + init_sync_kiocb(&kiocb, file);
> > > + kiocb.ki_pos = offset;
> > > + iov_iter_kvec(&iter, READ | ITER_KVEC, &iov, 1, count);
> > >
> > > + ret = file->f_op->integrity_read(&kiocb, &iter);
> > > + BUG_ON(ret == -EIOCBQUEUED);
> > > return ret;
> > > }
> > >
> > > --
> > > 2.7.4
> > >
> > >
>
--
Jan Kara <ja...@su...>
SUSE Labs, CR
|
|
From: Christoph H. <hc...@in...> - 2017-08-01 10:27:16
|
On Tue, Aug 01, 2017 at 12:20:36PM +0200, Roberto Sassu wrote: > This patch introduces a parser for RPM packages. It extracts the digests > from the RPMTAG_FILEDIGESTS header section and converts them to binary data > before adding them to the hash table. > > The advantage of this data type is that verifiers can determine who > produced that data, as headers are signed by Linux distributions vendors. > RPM headers signatures can be provided as digest list metadata. Err, parsing arbitrary file formats has no business in the kernel. |
|
From: Roberto S. <rob...@hu...> - 2017-08-01 10:22:01
|
This patch introduces a parser for RPM packages. It extracts the digests
from the RPMTAG_FILEDIGESTS header section and converts them to binary data
before adding them to the hash table.
The advantage of this data type is that verifiers can determine who
produced that data, as headers are signed by Linux distributions vendors.
RPM headers signatures can be provided as digest list metadata.
Signed-off-by: Roberto Sassu <rob...@hu...>
---
security/integrity/ima/ima_digest_list.c | 86 +++++++++++++++++++++++++++++++-
1 file changed, 85 insertions(+), 1 deletion(-)
diff --git a/security/integrity/ima/ima_digest_list.c b/security/integrity/ima/ima_digest_list.c
index c1ef79a..0b5916d 100644
--- a/security/integrity/ima/ima_digest_list.c
+++ b/security/integrity/ima/ima_digest_list.c
@@ -19,11 +19,13 @@
#include "ima.h"
#include "ima_template_lib.h"
+#define RPMTAG_FILEDIGESTS 1035
+
enum digest_metadata_fields {DATA_ALGO, DATA_DIGEST, DATA_SIGNATURE,
DATA_FILE_PATH, DATA_REF_ID, DATA_TYPE,
DATA__LAST};
-enum digest_data_types {DATA_TYPE_COMPACT_LIST};
+enum digest_data_types {DATA_TYPE_COMPACT_LIST, DATA_TYPE_RPM};
enum compact_list_entry_ids {COMPACT_LIST_ID_DIGEST};
@@ -33,6 +35,20 @@ struct compact_list_hdr {
u32 datalen;
} __packed;
+struct rpm_hdr {
+ u32 magic;
+ u32 reserved;
+ u32 tags;
+ u32 datasize;
+} __packed;
+
+struct rpm_entryinfo {
+ int32_t tag;
+ u32 type;
+ int32_t offset;
+ u32 count;
+} __packed;
+
static int ima_parse_compact_list(loff_t size, void *buf)
{
void *bufp = buf, *bufendp = buf + size;
@@ -80,6 +96,71 @@ static int ima_parse_compact_list(loff_t size, void *buf)
return 0;
}
+static int ima_parse_rpm(loff_t size, void *buf)
+{
+ void *bufp = buf, *bufendp = buf + size;
+ struct rpm_hdr *hdr = bufp;
+ u32 tags = be32_to_cpu(hdr->tags);
+ struct rpm_entryinfo *entry;
+ void *datap = bufp + sizeof(*hdr) + tags * sizeof(struct rpm_entryinfo);
+ int digest_len = hash_digest_size[ima_hash_algo];
+ u8 digest[digest_len];
+ int ret, i, j;
+
+ const unsigned char rpm_header_magic[8] = {
+ 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
+ };
+
+ if (size < sizeof(*hdr)) {
+ pr_err("Missing RPM header\n");
+ return -EINVAL;
+ }
+
+ if (memcmp(bufp, rpm_header_magic, sizeof(rpm_header_magic))) {
+ pr_err("Invalid RPM header\n");
+ return -EINVAL;
+ }
+
+ bufp += sizeof(*hdr);
+
+ for (i = 0; i < tags && (bufp + sizeof(*entry)) <= bufendp;
+ i++, bufp += sizeof(*entry)) {
+ entry = bufp;
+
+ if (be32_to_cpu(entry->tag) != RPMTAG_FILEDIGESTS)
+ continue;
+
+ datap += be32_to_cpu(entry->offset);
+
+ for (j = 0; j < be32_to_cpu(entry->count) &&
+ datap < bufendp; j++) {
+ if (strlen(datap) == 0) {
+ datap++;
+ continue;
+ }
+
+ if (datap + digest_len * 2 + 1 > bufendp) {
+ pr_err("RPM header read at invalid offset\n");
+ return -EINVAL;
+ }
+
+ ret = hex2bin(digest, datap, digest_len);
+ if (ret < 0)
+ return -EINVAL;
+
+ ret = ima_add_digest_data_entry(digest);
+ if (ret < 0 && ret != -EEXIST)
+ return ret;
+
+ datap += digest_len * 2 + 1;
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
static int ima_parse_digest_list_data(struct ima_field_data *data)
{
void *digest_list;
@@ -107,6 +188,9 @@ static int ima_parse_digest_list_data(struct ima_field_data *data)
case DATA_TYPE_COMPACT_LIST:
ret = ima_parse_compact_list(digest_list_size, digest_list);
break;
+ case DATA_TYPE_RPM:
+ ret = ima_parse_rpm(digest_list_size, digest_list);
+ break;
default:
pr_err("Parser for data type %d not implemented\n", data_type);
ret = -EINVAL;
--
2.9.3
|
|
From: Roberto S. <rob...@hu...> - 2017-08-01 10:18:24
|
Userspace applications will be able to load digest lists by supplying
their metadata.
Digest list metadata are:
- DATA_ALGO: algorithm of the digests to be uploaded
- DATA_DIGEST: digest of the file containing the digest list
- DATA_SIGNATURE: signature of the file containing the digest list
- DATA_FILE_PATH: pathname
- DATA_REF_ID: reference ID of the digest list
- DATA_TYPE: type of digest list
The new function ima_parse_digest_list_metadata() parses the metadata
and load each file individually. Then, it parses the data according
to the data type specified.
Since digest lists are measured, their digest is added to the hash table
so that IMA does not create a measurement entry for them (which would
affect the performance). The only measurement entry created will be
for the metadata.
Signed-off-by: Roberto Sassu <rob...@hu...>
---
include/linux/fs.h | 1 +
security/integrity/ima/Kconfig | 11 ++++
security/integrity/ima/Makefile | 1 +
security/integrity/ima/ima.h | 8 +++
security/integrity/ima/ima_digest_list.c | 105 +++++++++++++++++++++++++++++++
5 files changed, 126 insertions(+)
create mode 100644 security/integrity/ima/ima_digest_list.c
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 6e1fd5d..2eb6e7c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2751,6 +2751,7 @@ extern int do_pipe_flags(int *, int);
id(KEXEC_IMAGE, kexec-image) \
id(KEXEC_INITRAMFS, kexec-initramfs) \
id(POLICY, security-policy) \
+ id(DIGEST_LIST, security-digest-list) \
id(MAX_ID, )
#define __fid_enumify(ENUM, dummy) READING_ ## ENUM,
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 35ef693..8965dcc 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -227,3 +227,14 @@ config IMA_APPRAISE_SIGNED_INIT
default n
help
This option requires user-space init to be signed.
+
+config IMA_DIGEST_LIST
+ bool "Measure files depending on uploaded digest lists"
+ depends on IMA
+ default n
+ help
+ This option allows users to load digest lists. If a measured
+ file has the same digest of one from loaded lists, IMA will
+ not create a new measurement entry. A measurement entry will
+ be created only when digest lists are loaded (this entry
+ contains the digest of digest lists metadata).
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index 29f198b..00dbe3a 100644
--- a/security/integrity/ima/Makefile
+++ b/security/integrity/ima/Makefile
@@ -9,4 +9,5 @@ ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
ima_policy.o ima_template.o ima_template_lib.o
ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
+ima-$(CONFIG_IMA_DIGEST_LIST) += ima_digest_list.o
obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index a0c6808..9ecb7cc 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -157,6 +157,14 @@ int ima_restore_measurement_entry(struct ima_template_entry *entry);
int ima_restore_measurement_list(loff_t bufsize, void *buf);
struct ima_digest *ima_lookup_loaded_digest(u8 *digest);
int ima_add_digest_data_entry(u8 *digest);
+#ifdef CONFIG_IMA_DIGEST_LIST
+ssize_t ima_parse_digest_list_metadata(loff_t size, void *buf);
+#else
+static inline ssize_t ima_parse_digest_list_metadata(loff_t size, void *buf)
+{
+ return -ENOTSUPP;
+}
+#endif
int ima_measurements_show(struct seq_file *m, void *v);
unsigned long ima_get_binary_runtime_size(void);
int ima_init_template(void);
diff --git a/security/integrity/ima/ima_digest_list.c b/security/integrity/ima/ima_digest_list.c
new file mode 100644
index 0000000..3e1ff69b
--- /dev/null
+++ b/security/integrity/ima/ima_digest_list.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2017 Huawei Technologies Co. Ltd.
+ *
+ * Author: Roberto Sassu <rob...@hu...>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * File: ima_digest_list.c
+ * Functions to manage digest lists.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/vmalloc.h>
+
+#include "ima.h"
+#include "ima_template_lib.h"
+
+enum digest_metadata_fields {DATA_ALGO, DATA_DIGEST, DATA_SIGNATURE,
+ DATA_FILE_PATH, DATA_REF_ID, DATA_TYPE,
+ DATA__LAST};
+
+static int ima_parse_digest_list_data(struct ima_field_data *data)
+{
+ void *digest_list;
+ loff_t digest_list_size;
+ u16 data_algo = le16_to_cpu(*(u16 *)data[DATA_ALGO].data);
+ u16 data_type = le16_to_cpu(*(u16 *)data[DATA_TYPE].data);
+ int ret;
+
+ if (data_algo != ima_hash_algo) {
+ pr_err("Incompatible digest algorithm, expected %s\n",
+ hash_algo_name[ima_hash_algo]);
+ return -EINVAL;
+ }
+
+ ret = kernel_read_file_from_path(data[DATA_FILE_PATH].data,
+ &digest_list, &digest_list_size,
+ 0, READING_DIGEST_LIST);
+ if (ret < 0) {
+ pr_err("Unable to open file: %s (%d)",
+ data[DATA_FILE_PATH].data, ret);
+ return ret;
+ }
+
+ switch (data_type) {
+ default:
+ pr_err("Parser for data type %d not implemented\n", data_type);
+ ret = -EINVAL;
+ }
+
+ if (ret < 0) {
+ pr_err("Error parsing file: %s (%d)\n",
+ data[DATA_FILE_PATH].data, ret);
+ return ret;
+ }
+
+ vfree(digest_list);
+ return ret;
+}
+
+ssize_t ima_parse_digest_list_metadata(loff_t size, void *buf)
+{
+ struct ima_field_data entry;
+
+ struct ima_field_data entry_data[DATA__LAST] = {
+ [DATA_ALGO] = {.len = sizeof(u16)},
+ [DATA_TYPE] = {.len = sizeof(u16)},
+ };
+
+ DECLARE_BITMAP(data_mask, DATA__LAST);
+ void *bufp = buf, *bufendp = buf + size;
+ int ret;
+
+ bitmap_zero(data_mask, DATA__LAST);
+ bitmap_set(data_mask, DATA_ALGO, 1);
+ bitmap_set(data_mask, DATA_TYPE, 1);
+
+ ret = ima_parse_buf(bufp, bufendp, &bufp, 1, &entry, NULL, NULL,
+ ENFORCE_FIELDS, "metadata list entry");
+ if (ret < 0)
+ return ret;
+
+ ret = ima_parse_buf(entry.data, entry.data + entry.len, NULL,
+ DATA__LAST, entry_data, NULL, data_mask,
+ ENFORCE_FIELDS | ENFORCE_BUFEND,
+ "metadata entry data");
+ if (ret < 0)
+ goto out;
+
+ ret = ima_add_digest_data_entry(entry_data[DATA_DIGEST].data);
+ if (ret < 0) {
+ if (ret == -EEXIST)
+ ret = 0;
+
+ goto out;
+ }
+
+ ret = ima_parse_digest_list_data(entry_data);
+out:
+ return ret < 0 ? ret : bufp - buf;
+}
--
2.9.3
|
|
From: Mimi Z. <zo...@li...> - 2017-07-31 19:10:06
|
On Mon, 2017-07-31 at 09:01 +0200, Jan Kara wrote:
> On Wed 26-07-17 09:22:52, Mimi Zohar wrote:
> > From: Christoph Hellwig <hc...@ls...>
> >
> > Add a new ->integrity_read file operation to read data for integrity
> > hash collection. This is defined to be equivalent to ->read_iter,
> > except that it will be called with the i_rwsem held exclusively.
>
> The patch looks mostly good to me.
Thanks! Can I include your Ack-by?
> Just one question: How did you select
> filesystems that implement .integrity_read method?
Initially I started out looking at the fs/.../Kconfig, but after
spending a while looking at the number of filesystems, I gave up and
asked Christoph (offline) where to begin. I also compared the
measurement list from before and after the change and noticed some
missing file measurements (eg. ramfs, shmem, efivarfs).
> And I still maintain
> that it would be IMHO safer to not pretend we support IMA on gfs2 and ocfs2
> unless you either make sure they are mounted in local-only mode or figure
> out how to deal with proper cluster locking.
>
> Honza
Agreed. With patch 1/7 "ima: always measure and audit files in
policy", at least a file measurement containing a 0x00's hash value
will be included in the IMA measurement list.
thanks,
Mimi
> > Signed-off-by: Christoph Hellwig <hc...@ls...>
> > Cc: Matthew Garrett <mat...@ne...>
> > Cc: Jan Kara <ja...@su...>
> > Cc: "Theodore Ts'o" <ty...@mi...>
> > Cc: Andreas Dilger <adi...@di...>
> > Cc: Jaegeuk Kim <ja...@ke...>
> > Cc: Chao Yu <yu...@hu...>
> > Cc: Steven Whitehouse <swh...@re...>
> > Cc: Bob Peterson <rpe...@re...>
> > Cc: David Woodhouse <dw...@in...>
> > Cc: Dave Kleikamp <sh...@ke...>
> > Cc: Ryusuke Konishi <kon...@la...>
> > Cc: Mark Fasheh <mf...@ve...>
> > Cc: Joel Becker <jl...@ev...>
> > Cc: Richard Weinberger <ri...@no...>
> > Cc: "Darrick J. Wong" <dar...@or...>
> > Cc: Hugh Dickins <hu...@go...>
> > Cc: Chris Mason <cl...@fb...>
> > Signed-off-by: Mimi Zohar <zo...@li...>
> >
> > Changelog v4:
> > - define ext2/4 specific ->integrity_read functions.
> > - properly fail file open with O_DIRECT on filesystem not mounted
> > with "-o dax".
> >
> > ---
> > Changelog v3:
> > - define simple_read_iter_from_buffer
> > - replace the existing efivarfs ->read method with ->read_iter method.
> > - squashed other fs definitions of ->integrity_read with this patch.
> >
> > Changelog v2:
> > - change iovec to kvec
> >
> > Changelog v1:
> > - update the patch description, removing the concept that the presence of
> > ->integrity_read indicates that the file system can support IMA. (Mimi)
> >
> > fs/btrfs/file.c | 1 +
> > fs/efivarfs/file.c | 12 +++++++-----
> > fs/ext2/file.c | 17 +++++++++++++++++
> > fs/ext4/file.c | 23 +++++++++++++++++++++++
> > fs/f2fs/file.c | 1 +
> > fs/gfs2/file.c | 2 ++
> > fs/jffs2/file.c | 1 +
> > fs/jfs/file.c | 1 +
> > fs/libfs.c | 32 ++++++++++++++++++++++++++++++++
> > fs/nilfs2/file.c | 1 +
> > fs/ocfs2/file.c | 1 +
> > fs/ramfs/file-mmu.c | 1 +
> > fs/ramfs/file-nommu.c | 1 +
> > fs/ubifs/file.c | 1 +
> > fs/xfs/xfs_file.c | 21 +++++++++++++++++++++
> > include/linux/fs.h | 3 +++
> > mm/shmem.c | 1 +
> > security/integrity/iint.c | 20 ++++++++++++++------
> > 18 files changed, 129 insertions(+), 11 deletions(-)
> >
> > diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> > index 9e75d8a39aac..2542dc66c85c 100644
> > --- a/fs/btrfs/file.c
> > +++ b/fs/btrfs/file.c
> > @@ -3125,6 +3125,7 @@ const struct file_operations btrfs_file_operations = {
> > #endif
> > .clone_file_range = btrfs_clone_file_range,
> > .dedupe_file_range = btrfs_dedupe_file_range,
> > + .integrity_read = generic_file_read_iter,
> > };
> >
> > void btrfs_auto_defrag_exit(void)
> > diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c
> > index 5f22e74bbade..17955a92a5b3 100644
> > --- a/fs/efivarfs/file.c
> > +++ b/fs/efivarfs/file.c
> > @@ -64,9 +64,10 @@ static ssize_t efivarfs_file_write(struct file *file,
> > return bytes;
> > }
> >
> > -static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
> > - size_t count, loff_t *ppos)
> > +static ssize_t efivarfs_file_read_iter(struct kiocb *iocb,
> > + struct iov_iter *iter)
> > {
> > + struct file *file = iocb->ki_filp;
> > struct efivar_entry *var = file->private_data;
> > unsigned long datasize = 0;
> > u32 attributes;
> > @@ -96,8 +97,8 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
> > goto out_free;
> >
> > memcpy(data, &attributes, sizeof(attributes));
> > - size = simple_read_from_buffer(userbuf, count, ppos,
> > - data, datasize + sizeof(attributes));
> > + size = simple_read_iter_from_buffer(iocb, iter, data,
> > + datasize + sizeof(attributes));
> > out_free:
> > kfree(data);
> >
> > @@ -174,8 +175,9 @@ efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p)
> >
> > const struct file_operations efivarfs_file_operations = {
> > .open = simple_open,
> > - .read = efivarfs_file_read,
> > + .read_iter = efivarfs_file_read_iter,
> > .write = efivarfs_file_write,
> > .llseek = no_llseek,
> > .unlocked_ioctl = efivarfs_file_ioctl,
> > + .integrity_read = efivarfs_file_read_iter,
> > };
> > diff --git a/fs/ext2/file.c b/fs/ext2/file.c
> > index d34d32bdc944..111069de1973 100644
> > --- a/fs/ext2/file.c
> > +++ b/fs/ext2/file.c
> > @@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> > return generic_file_read_iter(iocb, to);
> > }
> >
> > +static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
> > + struct iov_iter *to)
> > +{
> > + struct inode *inode = file_inode(iocb->ki_filp);
> > +
> > + lockdep_assert_held(&inode->i_rwsem);
> > +#ifdef CONFIG_FS_DAX
> > + if (!iov_iter_count(to))
> > + return 0; /* skip atime */
> > +
> > + if (IS_DAX(iocb->ki_filp->f_mapping->host))
> > + return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
> > +#endif
> > + return generic_file_read_iter(iocb, to);
> > +}
> > +
> > static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
> > {
> > #ifdef CONFIG_FS_DAX
> > @@ -216,6 +232,7 @@ const struct file_operations ext2_file_operations = {
> > .get_unmapped_area = thp_get_unmapped_area,
> > .splice_read = generic_file_splice_read,
> > .splice_write = iter_file_splice_write,
> > + .integrity_read = ext2_file_integrity_read_iter,
> > };
> >
> > const struct inode_operations ext2_file_inode_operations = {
> > diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> > index 58294c9a7e1d..cb423fff935f 100644
> > --- a/fs/ext4/file.c
> > +++ b/fs/ext4/file.c
> > @@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> > return generic_file_read_iter(iocb, to);
> > }
> >
> > +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> > + struct iov_iter *to)
> > +{
> > + struct inode *inode = file_inode(iocb->ki_filp);
> > + int o_direct = iocb->ki_flags & IOCB_DIRECT;
> > +
> > + lockdep_assert_held(&inode->i_rwsem);
> > + if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> > + return -EIO;
> > +
> > + if (!iov_iter_count(to))
> > + return 0; /* skip atime */
> > +
> > +#ifdef CONFIG_FS_DAX
> > + if (IS_DAX(inode))
> > + return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> > +#endif
> > + if (o_direct)
> > + return -EINVAL;
> > + return generic_file_read_iter(iocb, to);
> > +}
> > +
> > /*
> > * Called when an inode is released. Note that this is different
> > * from ext4_file_open: open gets called at every open, but release
> > @@ -747,6 +769,7 @@ const struct file_operations ext4_file_operations = {
> > .splice_read = generic_file_splice_read,
> > .splice_write = iter_file_splice_write,
> > .fallocate = ext4_fallocate,
> > + .integrity_read = ext4_file_integrity_read_iter,
> > };
> >
> > const struct inode_operations ext4_file_inode_operations = {
> > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> > index 2706130c261b..82ea81da0b2d 100644
> > --- a/fs/f2fs/file.c
> > +++ b/fs/f2fs/file.c
> > @@ -2514,4 +2514,5 @@ const struct file_operations f2fs_file_operations = {
> > #endif
> > .splice_read = generic_file_splice_read,
> > .splice_write = iter_file_splice_write,
> > + .integrity_read = generic_file_read_iter,
> > };
> > diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
> > index c2062a108d19..9b49d09ba180 100644
> > --- a/fs/gfs2/file.c
> > +++ b/fs/gfs2/file.c
> > @@ -1124,6 +1124,7 @@ const struct file_operations gfs2_file_fops = {
> > .splice_write = gfs2_file_splice_write,
> > .setlease = simple_nosetlease,
> > .fallocate = gfs2_fallocate,
> > + .integrity_read = generic_file_read_iter,
> > };
> >
> > const struct file_operations gfs2_dir_fops = {
> > @@ -1152,6 +1153,7 @@ const struct file_operations gfs2_file_fops_nolock = {
> > .splice_write = gfs2_file_splice_write,
> > .setlease = generic_setlease,
> > .fallocate = gfs2_fallocate,
> > + .integrity_read = generic_file_read_iter,
> > };
> >
> > const struct file_operations gfs2_dir_fops_nolock = {
> > diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
> > index c12476e309c6..5a63034cccf5 100644
> > --- a/fs/jffs2/file.c
> > +++ b/fs/jffs2/file.c
> > @@ -57,6 +57,7 @@ const struct file_operations jffs2_file_operations =
> > .mmap = generic_file_readonly_mmap,
> > .fsync = jffs2_fsync,
> > .splice_read = generic_file_splice_read,
> > + .integrity_read = generic_file_read_iter,
> > };
> >
> > /* jffs2_file_inode_operations */
> > diff --git a/fs/jfs/file.c b/fs/jfs/file.c
> > index 739492c7a3fd..423512a810e4 100644
> > --- a/fs/jfs/file.c
> > +++ b/fs/jfs/file.c
> > @@ -162,4 +162,5 @@ const struct file_operations jfs_file_operations = {
> > #ifdef CONFIG_COMPAT
> > .compat_ioctl = jfs_compat_ioctl,
> > #endif
> > + .integrity_read = generic_file_read_iter,
> > };
> > diff --git a/fs/libfs.c b/fs/libfs.c
> > index 3aabe553fc45..99333264a0a7 100644
> > --- a/fs/libfs.c
> > +++ b/fs/libfs.c
> > @@ -16,6 +16,7 @@
> > #include <linux/exportfs.h>
> > #include <linux/writeback.h>
> > #include <linux/buffer_head.h> /* sync_mapping_buffers */
> > +#include <linux/uio.h>
> >
> > #include <linux/uaccess.h>
> >
> > @@ -676,6 +677,37 @@ ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
> > EXPORT_SYMBOL(simple_write_to_buffer);
> >
> > /**
> > + * simple_read_iter_from_buffer - copy data from the buffer to user space
> > + * @iocb: struct containing the file, the current position and other info
> > + * @to: the user space buffer to read to
> > + * @from: the buffer to read from
> > + * @available: the size of the buffer
> > + *
> > + * The simple_read_iter_from_buffer() function reads up to @available bytes
> > + * from the current buffer into the user space buffer.
> > + *
> > + * On success, the current buffer offset is advanced by the number of bytes
> > + * read, or a negative value is returned on error.
> > + **/
> > +ssize_t simple_read_iter_from_buffer(struct kiocb *iocb, struct iov_iter *to,
> > + const void *from, size_t available)
> > +{
> > + loff_t pos = iocb->ki_pos;
> > + size_t ret;
> > +
> > + if (pos < 0)
> > + return -EINVAL;
> > + if (pos >= available)
> > + return 0;
> > + ret = copy_to_iter(from + pos, available - pos, to);
> > + if (!ret && iov_iter_count(to))
> > + return -EFAULT;
> > + iocb->ki_pos = pos + ret;
> > + return ret;
> > +}
> > +EXPORT_SYMBOL(simple_read_iter_from_buffer);
> > +
> > +/**
> > * memory_read_from_buffer - copy data from the buffer
> > * @to: the kernel space buffer to read to
> > * @count: the maximum number of bytes to read
> > diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c
> > index c5fa3dee72fc..55e058ac487f 100644
> > --- a/fs/nilfs2/file.c
> > +++ b/fs/nilfs2/file.c
> > @@ -150,6 +150,7 @@ const struct file_operations nilfs_file_operations = {
> > /* .release = nilfs_release_file, */
> > .fsync = nilfs_sync_file,
> > .splice_read = generic_file_splice_read,
> > + .integrity_read = generic_file_read_iter,
> > };
> >
> > const struct inode_operations nilfs_file_inode_operations = {
> > diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
> > index bfeb647459d9..2832a7c92acd 100644
> > --- a/fs/ocfs2/file.c
> > +++ b/fs/ocfs2/file.c
> > @@ -2536,6 +2536,7 @@ const struct file_operations ocfs2_fops = {
> > .fallocate = ocfs2_fallocate,
> > .clone_file_range = ocfs2_file_clone_range,
> > .dedupe_file_range = ocfs2_file_dedupe_range,
> > + .integrity_read = ocfs2_file_read_iter,
> > };
> >
> > const struct file_operations ocfs2_dops = {
> > diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c
> > index 12af0490322f..4f24d1b589b1 100644
> > --- a/fs/ramfs/file-mmu.c
> > +++ b/fs/ramfs/file-mmu.c
> > @@ -47,6 +47,7 @@ const struct file_operations ramfs_file_operations = {
> > .splice_write = iter_file_splice_write,
> > .llseek = generic_file_llseek,
> > .get_unmapped_area = ramfs_mmu_get_unmapped_area,
> > + .integrity_read = generic_file_read_iter,
> > };
> >
> > const struct inode_operations ramfs_file_inode_operations = {
> > diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
> > index 2ef7ce75c062..5ee704fa84e0 100644
> > --- a/fs/ramfs/file-nommu.c
> > +++ b/fs/ramfs/file-nommu.c
> > @@ -50,6 +50,7 @@ const struct file_operations ramfs_file_operations = {
> > .splice_read = generic_file_splice_read,
> > .splice_write = iter_file_splice_write,
> > .llseek = generic_file_llseek,
> > + .integrity_read = generic_file_read_iter,
> > };
> >
> > const struct inode_operations ramfs_file_inode_operations = {
> > diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
> > index 8cad0b19b404..5e52a315e18b 100644
> > --- a/fs/ubifs/file.c
> > +++ b/fs/ubifs/file.c
> > @@ -1747,4 +1747,5 @@ const struct file_operations ubifs_file_operations = {
> > #ifdef CONFIG_COMPAT
> > .compat_ioctl = ubifs_compat_ioctl,
> > #endif
> > + .integrity_read = generic_file_read_iter,
> > };
> > diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> > index c4893e226fd8..0a6704b563d6 100644
> > --- a/fs/xfs/xfs_file.c
> > +++ b/fs/xfs/xfs_file.c
> > @@ -292,6 +292,26 @@ xfs_file_read_iter(
> > return ret;
> > }
> >
> > +static ssize_t
> > +xfs_integrity_read(
> > + struct kiocb *iocb,
> > + struct iov_iter *to)
> > +{
> > + struct inode *inode = file_inode(iocb->ki_filp);
> > + struct xfs_mount *mp = XFS_I(inode)->i_mount;
> > +
> > + lockdep_assert_held(&inode->i_rwsem);
> > +
> > + XFS_STATS_INC(mp, xs_read_calls);
> > +
> > + if (XFS_FORCED_SHUTDOWN(mp))
> > + return -EIO;
> > +
> > + if (IS_DAX(inode))
> > + return dax_iomap_rw(iocb, to, &xfs_iomap_ops);
> > + return generic_file_read_iter(iocb, to);
> > +}
> > +
> > /*
> > * Zero any on disk space between the current EOF and the new, larger EOF.
> > *
> > @@ -1175,6 +1195,7 @@ const struct file_operations xfs_file_operations = {
> > .fallocate = xfs_file_fallocate,
> > .clone_file_range = xfs_file_clone_range,
> > .dedupe_file_range = xfs_file_dedupe_range,
> > + .integrity_read = xfs_integrity_read,
> > };
> >
> > const struct file_operations xfs_dir_file_operations = {
> > diff --git a/include/linux/fs.h b/include/linux/fs.h
> > index 6e1fd5d21248..8d0d10e1dd93 100644
> > --- a/include/linux/fs.h
> > +++ b/include/linux/fs.h
> > @@ -1699,6 +1699,7 @@ struct file_operations {
> > u64);
> > ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
> > u64);
> > + ssize_t (*integrity_read)(struct kiocb *, struct iov_iter *);
> > } __randomize_layout;
> >
> > struct inode_operations {
> > @@ -3097,6 +3098,8 @@ extern void simple_release_fs(struct vfsmount **mount, int *count);
> >
> > extern ssize_t simple_read_from_buffer(void __user *to, size_t count,
> > loff_t *ppos, const void *from, size_t available);
> > +extern ssize_t simple_read_iter_from_buffer(struct kiocb *iocb,
> > + struct iov_iter *to, const void *from, size_t available);
> > extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
> > const void __user *from, size_t count);
> >
> > diff --git a/mm/shmem.c b/mm/shmem.c
> > index b0aa6075d164..805d99011ca4 100644
> > --- a/mm/shmem.c
> > +++ b/mm/shmem.c
> > @@ -3849,6 +3849,7 @@ static const struct file_operations shmem_file_operations = {
> > .splice_read = generic_file_splice_read,
> > .splice_write = iter_file_splice_write,
> > .fallocate = shmem_fallocate,
> > + .integrity_read = shmem_file_read_iter,
> > #endif
> > };
> >
> > diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> > index 6fc888ca468e..df04f35a1d40 100644
> > --- a/security/integrity/iint.c
> > +++ b/security/integrity/iint.c
> > @@ -21,6 +21,7 @@
> > #include <linux/rbtree.h>
> > #include <linux/file.h>
> > #include <linux/uaccess.h>
> > +#include <linux/uio.h>
> > #include "integrity.h"
> >
> > static struct rb_root integrity_iint_tree = RB_ROOT;
> > @@ -184,18 +185,25 @@ security_initcall(integrity_iintcache_init);
> > int integrity_kernel_read(struct file *file, loff_t offset,
> > void *addr, unsigned long count)
> > {
> > - mm_segment_t old_fs;
> > - char __user *buf = (char __user *)addr;
> > + struct inode *inode = file_inode(file);
> > + struct kvec iov = { .iov_base = addr, .iov_len = count };
> > + struct kiocb kiocb;
> > + struct iov_iter iter;
> > ssize_t ret;
> >
> > + lockdep_assert_held(&inode->i_rwsem);
> > +
> > if (!(file->f_mode & FMODE_READ))
> > return -EBADF;
> > + if (!file->f_op->integrity_read)
> > + return -EBADF;
> >
> > - old_fs = get_fs();
> > - set_fs(get_ds());
> > - ret = __vfs_read(file, buf, count, &offset);
> > - set_fs(old_fs);
> > + init_sync_kiocb(&kiocb, file);
> > + kiocb.ki_pos = offset;
> > + iov_iter_kvec(&iter, READ | ITER_KVEC, &iov, 1, count);
> >
> > + ret = file->f_op->integrity_read(&kiocb, &iter);
> > + BUG_ON(ret == -EIOCBQUEUED);
> > return ret;
> > }
> >
> > --
> > 2.7.4
> >
> >
|
|
From: Mimi Z. <zo...@li...> - 2017-07-31 12:02:49
|
On Sat, 2017-07-29 at 10:28 +0200, Fabio Vallone S224870 wrote:
> Hi all,
>
> I'm a master student in computer engineering at politecnico di torino.
> I'm doing my thesis on Remote Attestation for lightVM (especially for
> docker). During the development of my project I had the need to disable
> the two caches of Ima (the one looking the inode and the hashtable
> lookup), in order to have the file measured every time it is loaded (in
> my case this is useful because the same file can be loaded in different
> containers).
>
> I think that this feature can be useful also to other people so here is
> the patch (developed and tested on the latest version of the source
> code, i.e. v4.13 rc2):
Thank you for sharing this patch with us. The real solution is to
namespace IMA, including the hash table. Until IMA-measurement
namespacing is upstreamed, I assume this will be useful for others,
but, unfortunately, not something that I can upstream.
Below are a few reminders when posting patches in the future.
>
> From 1834f3d14cc94c1bd01999438f7ba0c0d3c9f717 Mon Sep 17 00:00:00 2001
> From: Fabio Vallone <fab...@st...>
> Date: Sat, 29 Jul 2017 10:01:01 +0200
> Subject: [PATCH] Kernel boot parameters to disable ima caches
Missing patch description.
>
> Signed-off-by: Fabio Vallone <fab...@st...>
> ---
> security/integrity/ima/ima.h | 2 ++
> security/integrity/ima/ima_init.c | 26 ++++++++++++++++++++++++++
> security/integrity/ima/ima_main.c | 8 ++++++++
> security/integrity/ima/ima_queue.c | 2 +-
> 4 files changed, 37 insertions(+), 1 deletion(-)
>
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index d52b487..2e969b2 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -57,6 +57,8 @@ extern int ima_initialized;
> extern int ima_used_chip;
> extern int ima_hash_algo;
> extern int ima_appraise;
> +extern int ima_cache1_enabled;
> +extern int ima_cache2_enabled;
>
> /* IMA event related data */
> struct ima_event_data {
> diff --git a/security/integrity/ima/ima_init.c
> b/security/integrity/ima/ima_init.c
> index 2967d49..ce5d7d8 100644
> --- a/security/integrity/ima/ima_init.c
> +++ b/security/integrity/ima/ima_init.c
> @@ -139,3 +139,29 @@ int __init ima_init(void)
>
> return ima_fs_init();
> }
> +// Disable cache 1 and cache 2
Refer to section 8 Commenting of the Documentation/process/coding-
style.rst as to style.
Mimi
> +static int __init ima_cache1_setup(char *str)
> +{
> + if(strncmp(str, "false", 5)==0){
> + printk("Disabling Cache1");
> + ima_cache1_enabled = 0;
> + }else{
> + ima_cache1_enabled = 1;
> + }
> +
> + return 1;
> +}
> +__setup("ima_cache1=", ima_cache1_setup);
> +
> +static int __init ima_cache2_setup(char *str)
> +{
> + if(strncmp(str, "false", 5)==0){
> + printk("Disabling Cache2");
> + ima_cache2_enabled = 0;
> + }else{
> + ima_cache1_enabled = 1;
> + }
> +
> + return 1;
> +}
> +__setup("ima_cache2=", ima_cache2_setup);
> diff --git a/security/integrity/ima/ima_main.c
> b/security/integrity/ima/ima_main.c
> index 2aebb79..be5dff0 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -28,6 +28,9 @@
> #include "ima.h"
>
> int ima_initialized;
> +int ima_cache1_enabled = 1;
> +int ima_cache2_enabled = 1;
> +
>
> #ifdef CONFIG_IMA_APPRAISE
> int ima_appraise = IMA_APPRAISE_ENFORCE;
> @@ -253,6 +256,11 @@ static int process_measurement(struct file *file,
> char *buf, loff_t size,
> if (action & IMA_AUDIT)
> ima_audit_measurement(iint, pathname);
>
> + //Flush Inode For next Measurement if cache1 is disabled
> + if(ima_cache1_enabled == 0)
> + iint->measured_pcrs = 0;
> +
> +
> out_digsig:
> if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG) &&
> !(iint->flags & IMA_NEW_FILE))
> diff --git a/security/integrity/ima/ima_queue.c
> b/security/integrity/ima/ima_queue.c
> index a02a86d..7105587 100644
> --- a/security/integrity/ima/ima_queue.c
> +++ b/security/integrity/ima/ima_queue.c
> @@ -172,7 +172,7 @@ int ima_add_template_entry(struct ima_template_entry
> *entry, int violation,
> mutex_lock(&ima_extend_list_mutex);
> if (!violation) {
> memcpy(digest, entry->digest, sizeof(digest));
> - if (ima_lookup_digest_entry(digest, entry->pcr)) {
> + if (ima_cache2_enabled==1 && ima_lookup_digest_entry(digest,
> entry->pcr)) {
> audit_cause = "hash_exists";
> result = -EEXIST;
> goto out;
|
|
From: Mimi Z. <zo...@li...> - 2017-07-31 11:32:17
|
On Fri, 2017-07-28 at 14:19 +0000, Magalhaes, Guilherme (Brazil R&D- CL) wrote: > > > Each measurement entry in the list could have new fields to identify > > > the namespace. Since the namespaces can be reused, a timestamp or > > > others fields could be added to uniquely identify the namespace id. > > > > The more fields included in the measurement list, the more > > measurements will be added to the measurement list. Wouldn't it be > > enough to know that a certain file has been accessed/executed on the > > system and base any analytics/forensics on the IMA-audit data. > > With the recursive application of policy through the namespace hierarchy, > a measurement added to the parent namespace could be misleading since > the file pathname makes sense in the current namespace but possibly not > for the parent namespace. Fair enough. > This is the reason why I believe some new field > might be needed in the IMA template format to indicate or uniquely > identify the namespace. I would probably include information to uniquely identify the file (eg. UUID, mountpoint), not the namespace. Mimi |
|
From: Jan K. <ja...@su...> - 2017-07-31 07:02:02
|
On Wed 26-07-17 09:22:52, Mimi Zohar wrote:
> From: Christoph Hellwig <hc...@ls...>
>
> Add a new ->integrity_read file operation to read data for integrity
> hash collection. This is defined to be equivalent to ->read_iter,
> except that it will be called with the i_rwsem held exclusively.
The patch looks mostly good to me. Just one question: How did you select
filesystems that implement .integrity_read method? And I still maintain
that it would be IMHO safer to not pretend we support IMA on gfs2 and ocfs2
unless you either make sure they are mounted in local-only mode or figure
out how to deal with proper cluster locking.
Honza
> Signed-off-by: Christoph Hellwig <hc...@ls...>
> Cc: Matthew Garrett <mat...@ne...>
> Cc: Jan Kara <ja...@su...>
> Cc: "Theodore Ts'o" <ty...@mi...>
> Cc: Andreas Dilger <adi...@di...>
> Cc: Jaegeuk Kim <ja...@ke...>
> Cc: Chao Yu <yu...@hu...>
> Cc: Steven Whitehouse <swh...@re...>
> Cc: Bob Peterson <rpe...@re...>
> Cc: David Woodhouse <dw...@in...>
> Cc: Dave Kleikamp <sh...@ke...>
> Cc: Ryusuke Konishi <kon...@la...>
> Cc: Mark Fasheh <mf...@ve...>
> Cc: Joel Becker <jl...@ev...>
> Cc: Richard Weinberger <ri...@no...>
> Cc: "Darrick J. Wong" <dar...@or...>
> Cc: Hugh Dickins <hu...@go...>
> Cc: Chris Mason <cl...@fb...>
> Signed-off-by: Mimi Zohar <zo...@li...>
>
> Changelog v4:
> - define ext2/4 specific ->integrity_read functions.
> - properly fail file open with O_DIRECT on filesystem not mounted
> with "-o dax".
>
> ---
> Changelog v3:
> - define simple_read_iter_from_buffer
> - replace the existing efivarfs ->read method with ->read_iter method.
> - squashed other fs definitions of ->integrity_read with this patch.
>
> Changelog v2:
> - change iovec to kvec
>
> Changelog v1:
> - update the patch description, removing the concept that the presence of
> ->integrity_read indicates that the file system can support IMA. (Mimi)
>
> fs/btrfs/file.c | 1 +
> fs/efivarfs/file.c | 12 +++++++-----
> fs/ext2/file.c | 17 +++++++++++++++++
> fs/ext4/file.c | 23 +++++++++++++++++++++++
> fs/f2fs/file.c | 1 +
> fs/gfs2/file.c | 2 ++
> fs/jffs2/file.c | 1 +
> fs/jfs/file.c | 1 +
> fs/libfs.c | 32 ++++++++++++++++++++++++++++++++
> fs/nilfs2/file.c | 1 +
> fs/ocfs2/file.c | 1 +
> fs/ramfs/file-mmu.c | 1 +
> fs/ramfs/file-nommu.c | 1 +
> fs/ubifs/file.c | 1 +
> fs/xfs/xfs_file.c | 21 +++++++++++++++++++++
> include/linux/fs.h | 3 +++
> mm/shmem.c | 1 +
> security/integrity/iint.c | 20 ++++++++++++++------
> 18 files changed, 129 insertions(+), 11 deletions(-)
>
> diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> index 9e75d8a39aac..2542dc66c85c 100644
> --- a/fs/btrfs/file.c
> +++ b/fs/btrfs/file.c
> @@ -3125,6 +3125,7 @@ const struct file_operations btrfs_file_operations = {
> #endif
> .clone_file_range = btrfs_clone_file_range,
> .dedupe_file_range = btrfs_dedupe_file_range,
> + .integrity_read = generic_file_read_iter,
> };
>
> void btrfs_auto_defrag_exit(void)
> diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c
> index 5f22e74bbade..17955a92a5b3 100644
> --- a/fs/efivarfs/file.c
> +++ b/fs/efivarfs/file.c
> @@ -64,9 +64,10 @@ static ssize_t efivarfs_file_write(struct file *file,
> return bytes;
> }
>
> -static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
> - size_t count, loff_t *ppos)
> +static ssize_t efivarfs_file_read_iter(struct kiocb *iocb,
> + struct iov_iter *iter)
> {
> + struct file *file = iocb->ki_filp;
> struct efivar_entry *var = file->private_data;
> unsigned long datasize = 0;
> u32 attributes;
> @@ -96,8 +97,8 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
> goto out_free;
>
> memcpy(data, &attributes, sizeof(attributes));
> - size = simple_read_from_buffer(userbuf, count, ppos,
> - data, datasize + sizeof(attributes));
> + size = simple_read_iter_from_buffer(iocb, iter, data,
> + datasize + sizeof(attributes));
> out_free:
> kfree(data);
>
> @@ -174,8 +175,9 @@ efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p)
>
> const struct file_operations efivarfs_file_operations = {
> .open = simple_open,
> - .read = efivarfs_file_read,
> + .read_iter = efivarfs_file_read_iter,
> .write = efivarfs_file_write,
> .llseek = no_llseek,
> .unlocked_ioctl = efivarfs_file_ioctl,
> + .integrity_read = efivarfs_file_read_iter,
> };
> diff --git a/fs/ext2/file.c b/fs/ext2/file.c
> index d34d32bdc944..111069de1973 100644
> --- a/fs/ext2/file.c
> +++ b/fs/ext2/file.c
> @@ -192,6 +192,22 @@ static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> return generic_file_read_iter(iocb, to);
> }
>
> +static ssize_t ext2_file_integrity_read_iter(struct kiocb *iocb,
> + struct iov_iter *to)
> +{
> + struct inode *inode = file_inode(iocb->ki_filp);
> +
> + lockdep_assert_held(&inode->i_rwsem);
> +#ifdef CONFIG_FS_DAX
> + if (!iov_iter_count(to))
> + return 0; /* skip atime */
> +
> + if (IS_DAX(iocb->ki_filp->f_mapping->host))
> + return dax_iomap_rw(iocb, to, &ext2_iomap_ops);
> +#endif
> + return generic_file_read_iter(iocb, to);
> +}
> +
> static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
> {
> #ifdef CONFIG_FS_DAX
> @@ -216,6 +232,7 @@ const struct file_operations ext2_file_operations = {
> .get_unmapped_area = thp_get_unmapped_area,
> .splice_read = generic_file_splice_read,
> .splice_write = iter_file_splice_write,
> + .integrity_read = ext2_file_integrity_read_iter,
> };
>
> const struct inode_operations ext2_file_inode_operations = {
> diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> index 58294c9a7e1d..cb423fff935f 100644
> --- a/fs/ext4/file.c
> +++ b/fs/ext4/file.c
> @@ -74,6 +74,28 @@ static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
> return generic_file_read_iter(iocb, to);
> }
>
> +static ssize_t ext4_file_integrity_read_iter(struct kiocb *iocb,
> + struct iov_iter *to)
> +{
> + struct inode *inode = file_inode(iocb->ki_filp);
> + int o_direct = iocb->ki_flags & IOCB_DIRECT;
> +
> + lockdep_assert_held(&inode->i_rwsem);
> + if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
> + return -EIO;
> +
> + if (!iov_iter_count(to))
> + return 0; /* skip atime */
> +
> +#ifdef CONFIG_FS_DAX
> + if (IS_DAX(inode))
> + return dax_iomap_rw(iocb, to, &ext4_iomap_ops);
> +#endif
> + if (o_direct)
> + return -EINVAL;
> + return generic_file_read_iter(iocb, to);
> +}
> +
> /*
> * Called when an inode is released. Note that this is different
> * from ext4_file_open: open gets called at every open, but release
> @@ -747,6 +769,7 @@ const struct file_operations ext4_file_operations = {
> .splice_read = generic_file_splice_read,
> .splice_write = iter_file_splice_write,
> .fallocate = ext4_fallocate,
> + .integrity_read = ext4_file_integrity_read_iter,
> };
>
> const struct inode_operations ext4_file_inode_operations = {
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index 2706130c261b..82ea81da0b2d 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -2514,4 +2514,5 @@ const struct file_operations f2fs_file_operations = {
> #endif
> .splice_read = generic_file_splice_read,
> .splice_write = iter_file_splice_write,
> + .integrity_read = generic_file_read_iter,
> };
> diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
> index c2062a108d19..9b49d09ba180 100644
> --- a/fs/gfs2/file.c
> +++ b/fs/gfs2/file.c
> @@ -1124,6 +1124,7 @@ const struct file_operations gfs2_file_fops = {
> .splice_write = gfs2_file_splice_write,
> .setlease = simple_nosetlease,
> .fallocate = gfs2_fallocate,
> + .integrity_read = generic_file_read_iter,
> };
>
> const struct file_operations gfs2_dir_fops = {
> @@ -1152,6 +1153,7 @@ const struct file_operations gfs2_file_fops_nolock = {
> .splice_write = gfs2_file_splice_write,
> .setlease = generic_setlease,
> .fallocate = gfs2_fallocate,
> + .integrity_read = generic_file_read_iter,
> };
>
> const struct file_operations gfs2_dir_fops_nolock = {
> diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
> index c12476e309c6..5a63034cccf5 100644
> --- a/fs/jffs2/file.c
> +++ b/fs/jffs2/file.c
> @@ -57,6 +57,7 @@ const struct file_operations jffs2_file_operations =
> .mmap = generic_file_readonly_mmap,
> .fsync = jffs2_fsync,
> .splice_read = generic_file_splice_read,
> + .integrity_read = generic_file_read_iter,
> };
>
> /* jffs2_file_inode_operations */
> diff --git a/fs/jfs/file.c b/fs/jfs/file.c
> index 739492c7a3fd..423512a810e4 100644
> --- a/fs/jfs/file.c
> +++ b/fs/jfs/file.c
> @@ -162,4 +162,5 @@ const struct file_operations jfs_file_operations = {
> #ifdef CONFIG_COMPAT
> .compat_ioctl = jfs_compat_ioctl,
> #endif
> + .integrity_read = generic_file_read_iter,
> };
> diff --git a/fs/libfs.c b/fs/libfs.c
> index 3aabe553fc45..99333264a0a7 100644
> --- a/fs/libfs.c
> +++ b/fs/libfs.c
> @@ -16,6 +16,7 @@
> #include <linux/exportfs.h>
> #include <linux/writeback.h>
> #include <linux/buffer_head.h> /* sync_mapping_buffers */
> +#include <linux/uio.h>
>
> #include <linux/uaccess.h>
>
> @@ -676,6 +677,37 @@ ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
> EXPORT_SYMBOL(simple_write_to_buffer);
>
> /**
> + * simple_read_iter_from_buffer - copy data from the buffer to user space
> + * @iocb: struct containing the file, the current position and other info
> + * @to: the user space buffer to read to
> + * @from: the buffer to read from
> + * @available: the size of the buffer
> + *
> + * The simple_read_iter_from_buffer() function reads up to @available bytes
> + * from the current buffer into the user space buffer.
> + *
> + * On success, the current buffer offset is advanced by the number of bytes
> + * read, or a negative value is returned on error.
> + **/
> +ssize_t simple_read_iter_from_buffer(struct kiocb *iocb, struct iov_iter *to,
> + const void *from, size_t available)
> +{
> + loff_t pos = iocb->ki_pos;
> + size_t ret;
> +
> + if (pos < 0)
> + return -EINVAL;
> + if (pos >= available)
> + return 0;
> + ret = copy_to_iter(from + pos, available - pos, to);
> + if (!ret && iov_iter_count(to))
> + return -EFAULT;
> + iocb->ki_pos = pos + ret;
> + return ret;
> +}
> +EXPORT_SYMBOL(simple_read_iter_from_buffer);
> +
> +/**
> * memory_read_from_buffer - copy data from the buffer
> * @to: the kernel space buffer to read to
> * @count: the maximum number of bytes to read
> diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c
> index c5fa3dee72fc..55e058ac487f 100644
> --- a/fs/nilfs2/file.c
> +++ b/fs/nilfs2/file.c
> @@ -150,6 +150,7 @@ const struct file_operations nilfs_file_operations = {
> /* .release = nilfs_release_file, */
> .fsync = nilfs_sync_file,
> .splice_read = generic_file_splice_read,
> + .integrity_read = generic_file_read_iter,
> };
>
> const struct inode_operations nilfs_file_inode_operations = {
> diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
> index bfeb647459d9..2832a7c92acd 100644
> --- a/fs/ocfs2/file.c
> +++ b/fs/ocfs2/file.c
> @@ -2536,6 +2536,7 @@ const struct file_operations ocfs2_fops = {
> .fallocate = ocfs2_fallocate,
> .clone_file_range = ocfs2_file_clone_range,
> .dedupe_file_range = ocfs2_file_dedupe_range,
> + .integrity_read = ocfs2_file_read_iter,
> };
>
> const struct file_operations ocfs2_dops = {
> diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c
> index 12af0490322f..4f24d1b589b1 100644
> --- a/fs/ramfs/file-mmu.c
> +++ b/fs/ramfs/file-mmu.c
> @@ -47,6 +47,7 @@ const struct file_operations ramfs_file_operations = {
> .splice_write = iter_file_splice_write,
> .llseek = generic_file_llseek,
> .get_unmapped_area = ramfs_mmu_get_unmapped_area,
> + .integrity_read = generic_file_read_iter,
> };
>
> const struct inode_operations ramfs_file_inode_operations = {
> diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
> index 2ef7ce75c062..5ee704fa84e0 100644
> --- a/fs/ramfs/file-nommu.c
> +++ b/fs/ramfs/file-nommu.c
> @@ -50,6 +50,7 @@ const struct file_operations ramfs_file_operations = {
> .splice_read = generic_file_splice_read,
> .splice_write = iter_file_splice_write,
> .llseek = generic_file_llseek,
> + .integrity_read = generic_file_read_iter,
> };
>
> const struct inode_operations ramfs_file_inode_operations = {
> diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
> index 8cad0b19b404..5e52a315e18b 100644
> --- a/fs/ubifs/file.c
> +++ b/fs/ubifs/file.c
> @@ -1747,4 +1747,5 @@ const struct file_operations ubifs_file_operations = {
> #ifdef CONFIG_COMPAT
> .compat_ioctl = ubifs_compat_ioctl,
> #endif
> + .integrity_read = generic_file_read_iter,
> };
> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> index c4893e226fd8..0a6704b563d6 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -292,6 +292,26 @@ xfs_file_read_iter(
> return ret;
> }
>
> +static ssize_t
> +xfs_integrity_read(
> + struct kiocb *iocb,
> + struct iov_iter *to)
> +{
> + struct inode *inode = file_inode(iocb->ki_filp);
> + struct xfs_mount *mp = XFS_I(inode)->i_mount;
> +
> + lockdep_assert_held(&inode->i_rwsem);
> +
> + XFS_STATS_INC(mp, xs_read_calls);
> +
> + if (XFS_FORCED_SHUTDOWN(mp))
> + return -EIO;
> +
> + if (IS_DAX(inode))
> + return dax_iomap_rw(iocb, to, &xfs_iomap_ops);
> + return generic_file_read_iter(iocb, to);
> +}
> +
> /*
> * Zero any on disk space between the current EOF and the new, larger EOF.
> *
> @@ -1175,6 +1195,7 @@ const struct file_operations xfs_file_operations = {
> .fallocate = xfs_file_fallocate,
> .clone_file_range = xfs_file_clone_range,
> .dedupe_file_range = xfs_file_dedupe_range,
> + .integrity_read = xfs_integrity_read,
> };
>
> const struct file_operations xfs_dir_file_operations = {
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 6e1fd5d21248..8d0d10e1dd93 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1699,6 +1699,7 @@ struct file_operations {
> u64);
> ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
> u64);
> + ssize_t (*integrity_read)(struct kiocb *, struct iov_iter *);
> } __randomize_layout;
>
> struct inode_operations {
> @@ -3097,6 +3098,8 @@ extern void simple_release_fs(struct vfsmount **mount, int *count);
>
> extern ssize_t simple_read_from_buffer(void __user *to, size_t count,
> loff_t *ppos, const void *from, size_t available);
> +extern ssize_t simple_read_iter_from_buffer(struct kiocb *iocb,
> + struct iov_iter *to, const void *from, size_t available);
> extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
> const void __user *from, size_t count);
>
> diff --git a/mm/shmem.c b/mm/shmem.c
> index b0aa6075d164..805d99011ca4 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -3849,6 +3849,7 @@ static const struct file_operations shmem_file_operations = {
> .splice_read = generic_file_splice_read,
> .splice_write = iter_file_splice_write,
> .fallocate = shmem_fallocate,
> + .integrity_read = shmem_file_read_iter,
> #endif
> };
>
> diff --git a/security/integrity/iint.c b/security/integrity/iint.c
> index 6fc888ca468e..df04f35a1d40 100644
> --- a/security/integrity/iint.c
> +++ b/security/integrity/iint.c
> @@ -21,6 +21,7 @@
> #include <linux/rbtree.h>
> #include <linux/file.h>
> #include <linux/uaccess.h>
> +#include <linux/uio.h>
> #include "integrity.h"
>
> static struct rb_root integrity_iint_tree = RB_ROOT;
> @@ -184,18 +185,25 @@ security_initcall(integrity_iintcache_init);
> int integrity_kernel_read(struct file *file, loff_t offset,
> void *addr, unsigned long count)
> {
> - mm_segment_t old_fs;
> - char __user *buf = (char __user *)addr;
> + struct inode *inode = file_inode(file);
> + struct kvec iov = { .iov_base = addr, .iov_len = count };
> + struct kiocb kiocb;
> + struct iov_iter iter;
> ssize_t ret;
>
> + lockdep_assert_held(&inode->i_rwsem);
> +
> if (!(file->f_mode & FMODE_READ))
> return -EBADF;
> + if (!file->f_op->integrity_read)
> + return -EBADF;
>
> - old_fs = get_fs();
> - set_fs(get_ds());
> - ret = __vfs_read(file, buf, count, &offset);
> - set_fs(old_fs);
> + init_sync_kiocb(&kiocb, file);
> + kiocb.ki_pos = offset;
> + iov_iter_kvec(&iter, READ | ITER_KVEC, &iov, 1, count);
>
> + ret = file->f_op->integrity_read(&kiocb, &iter);
> + BUG_ON(ret == -EIOCBQUEUED);
> return ret;
> }
>
> --
> 2.7.4
>
>
--
Jan Kara <ja...@su...>
SUSE Labs, CR
|
|
From: Mimi Z. <zo...@li...> - 2017-07-30 14:30:17
|
On Thu, 2017-07-06 at 19:17 -0300, Thiago Jung Bauermann wrote:
> This patch introduces the modsig keyword to the IMA policy syntax to
> specify that a given hook should expect the file to have the IMA signature
> appended to it. Here is how it can be used in a rule:
>
> appraise func=KEXEC_KERNEL_CHECK appraise_type=modsig|imasig
>
> With this rule, IMA will accept either an appended signature or a signature
> stored in the extended attribute. In that case, it will first check whether
> there is an appended signature, and if not it will read it from the
> extended attribute.
>
> The format of the appended signature is the same used for signed kernel
> modules. This means that the file can be signed with the scripts/sign-file
> tool, with a command line such as this:
>
> $ sign-file sha256 privkey_ima.pem x509_ima.der vmlinux
>
> This code only works for files that are hashed from a memory buffer, not
> for files that are read from disk at the time of hash calculation. In other
> words, only hooks that use kernel_read_file can support appended
> signatures. This means that only FIRMWARE_CHECK, KEXEC_KERNEL_CHECK,
> KEXEC_INITRAMFS_CHECK and POLICY_CHECK can be supported.
>
> This feature warrants a separate config option because enabling it brings
> in many other config options.
>
> Signed-off-by: Thiago Jung Bauermann <bau...@li...>
> ---
> security/integrity/ima/Kconfig | 13 +++
> security/integrity/ima/Makefile | 1 +
> security/integrity/ima/ima.h | 60 ++++++++++--
> security/integrity/ima/ima_appraise.c | 102 ++++++++++++++++++---
> security/integrity/ima/ima_main.c | 7 +-
> security/integrity/ima/ima_modsig.c | 147 ++++++++++++++++++++++++++++++
> security/integrity/ima/ima_policy.c | 26 ++++--
> security/integrity/ima/ima_template_lib.c | 14 ++-
> security/integrity/integrity.h | 4 +-
> 9 files changed, 343 insertions(+), 31 deletions(-)
>
> diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
> index 35ef69312811..55f734a6124b 100644
> --- a/security/integrity/ima/Kconfig
> +++ b/security/integrity/ima/Kconfig
> @@ -163,6 +163,19 @@ config IMA_APPRAISE_BOOTPARAM
> This option enables the different "ima_appraise=" modes
> (eg. fix, log) from the boot command line.
>
> +config IMA_APPRAISE_MODSIG
> + bool "Support module-style signatures for appraisal"
> + depends on IMA_APPRAISE
> + depends on INTEGRITY_ASYMMETRIC_KEYS
> + select PKCS7_MESSAGE_PARSER
> + select MODULE_SIG_FORMAT
> + default n
> + help
> + Adds support for signatures appended to files. The format of the
> + appended signature is the same used for signed kernel modules.
> + The modsig keyword can be used in the IMA policy to allow a hook
> + to accept such signatures.
> +
> config IMA_TRUSTED_KEYRING
> bool "Require all keys on the .ima keyring be signed (deprecated)"
> depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
> diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
> index 29f198bde02b..c72026acecc3 100644
> --- a/security/integrity/ima/Makefile
> +++ b/security/integrity/ima/Makefile
> @@ -8,5 +8,6 @@ obj-$(CONFIG_IMA) += ima.o
> ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
> ima_policy.o ima_template.o ima_template_lib.o
> ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
> +ima-$(CONFIG_IMA_APPRAISE_MODSIG) += ima_modsig.o
> ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
> obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index d52b487ad259..1e1e7c41ca19 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -190,6 +190,8 @@ enum ima_hooks {
> __ima_hooks(__ima_hook_enumify)
> };
>
> +extern const char *const func_tokens[];
> +
> /* LIM API function definitions */
> int ima_get_action(struct inode *inode, int mask,
> enum ima_hooks func, int *pcr);
> @@ -236,9 +238,10 @@ int ima_policy_show(struct seq_file *m, void *v);
> #ifdef CONFIG_IMA_APPRAISE
> int ima_appraise_measurement(enum ima_hooks func,
> struct integrity_iint_cache *iint,
> - struct file *file, const unsigned char *filename,
> - struct evm_ima_xattr_data *xattr_value,
> - int xattr_len, int opened);
> + struct file *file, const void *buf, loff_t size,
> + const unsigned char *filename,
> + struct evm_ima_xattr_data **xattr_value,
> + int *xattr_len, int opened);
> int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
> void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
> enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
> @@ -248,13 +251,26 @@ enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
> int ima_read_xattr(struct dentry *dentry,
> struct evm_ima_xattr_data **xattr_value);
>
> +#ifdef CONFIG_IMA_APPRAISE_MODSIG
> +bool ima_hook_supports_modsig(enum ima_hooks func);
> +int ima_read_modsig(const void *buf, loff_t buf_len,
> + struct evm_ima_xattr_data **xattr_value,
> + int *xattr_len);
> +int ima_modsig_serialize_data(struct evm_ima_xattr_data *hdr,
> + struct evm_ima_xattr_data **data, int *data_len);
> +int ima_modsig_verify(const unsigned int keyring_id,
> + struct evm_ima_xattr_data *hdr);
> +void ima_free_xattr_data(struct evm_ima_xattr_data *hdr);
> +#endif
> +
> #else
> static inline int ima_appraise_measurement(enum ima_hooks func,
> struct integrity_iint_cache *iint,
> - struct file *file,
> + struct file *file, const void *buf,
> + loff_t size,
> const unsigned char *filename,
> - struct evm_ima_xattr_data *xattr_value,
> - int xattr_len, int opened)
> + struct evm_ima_xattr_data **xattr_value,
> + int *xattr_len, int opened)
> {
> return INTEGRITY_UNKNOWN;
> }
> @@ -291,6 +307,38 @@ static inline int ima_read_xattr(struct dentry *dentry,
>
> #endif /* CONFIG_IMA_APPRAISE */
>
> +#ifndef CONFIG_IMA_APPRAISE_MODSIG
> +static inline bool ima_hook_supports_modsig(enum ima_hooks func)
> +{
> + return false;
> +}
> +
> +static inline int ima_read_modsig(const void *buf, loff_t buf_len,
> + struct evm_ima_xattr_data **xattr_value,
> + int *xattr_len)
> +{
> + return -ENOTSUPP;
> +}
> +
> +static inline int ima_modsig_serialize_data(struct evm_ima_xattr_data *hdr,
> + struct evm_ima_xattr_data **data,
> + int *data_len)
> +{
> + return -ENOTSUPP;
> +}
> +
> +static inline int ima_modsig_verify(const unsigned int keyring_id,
> + struct evm_ima_xattr_data *hdr)
> +{
> + return -ENOTSUPP;
> +}
> +
> +static inline void ima_free_xattr_data(struct evm_ima_xattr_data *hdr)
> +{
> + kfree(hdr);
> +}
> +#endif
> +
> /* LSM based policy rules require audit */
> #ifdef CONFIG_IMA_LSM_RULES
>
> diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
> index 87d2b601cf8e..b80aae429314 100644
> --- a/security/integrity/ima/ima_appraise.c
> +++ b/security/integrity/ima/ima_appraise.c
> @@ -200,18 +200,40 @@ int ima_read_xattr(struct dentry *dentry,
> */
> int ima_appraise_measurement(enum ima_hooks func,
> struct integrity_iint_cache *iint,
> - struct file *file, const unsigned char *filename,
> - struct evm_ima_xattr_data *xattr_value,
> - int xattr_len, int opened)
> + struct file *file, const void *buf, loff_t size,
> + const unsigned char *filename,
> + struct evm_ima_xattr_data **xattr_value_,
> + int *xattr_len_, int opened)
> {
> static const char op[] = "appraise_data";
> char *cause = "unknown";
> struct dentry *dentry = file_dentry(file);
> struct inode *inode = d_backing_inode(dentry);
> enum integrity_status status = INTEGRITY_UNKNOWN;
> - int rc = xattr_len, hash_start = 0;
> + struct evm_ima_xattr_data *xattr_value = *xattr_value_;
> + int xattr_len = *xattr_len_, rc = xattr_len, hash_start = 0;
> + bool appraising_modsig = false;
> + void *xattr_value_evm;
> + size_t xattr_len_evm;
> +
> + if (iint->flags & IMA_MODSIG_ALLOWED) {
> + /*
> + * Not supposed to happen. Hooks that support modsig are
> + * whitelisted when parsing the policy using
> + * ima_hooks_supports_modsig.
> + */
> + if (!buf || !size)
> + WARN_ONCE(true, "%s doesn't support modsig\n",
> + func_tokens[func]);
ima _appraise_measurement() is getting kind of long. Is there any
reason we can't move this comment and test to ima_read_modsig()?
> + else if (!ima_read_modsig(buf, size,
> + &xattr_value, &xattr_len)) {
> + appraising_modsig = true;
> + rc = xattr_len;
> + }
> + }
>
> - if (!(inode->i_opflags & IOP_XATTR))
> + /* If not appraising a modsig, we need an xattr. */
> + if (!appraising_modsig && !(inode->i_opflags & IOP_XATTR))
> return INTEGRITY_UNKNOWN;
>
> if (rc <= 0) {
> @@ -229,8 +251,24 @@ int ima_appraise_measurement(enum ima_hooks func,
> goto out;
> }
>
> - status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint);
> - if ((status != INTEGRITY_PASS) && (status != INTEGRITY_UNKNOWN)) {
> + /*
> + * Appended signatures aren't protected by EVM but we still call
> + * evm_verifyxattr to check other security xattrs, if they exist.
> + */
> + if (appraising_modsig) {
> + xattr_value_evm = NULL;
> + xattr_len_evm = 0;
> + } else {
> + xattr_value_evm = xattr_value;
> + xattr_len_evm = xattr_len;
> + }
> +
> + status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value_evm,
> + xattr_len_evm, iint);
> + if (appraising_modsig && status == INTEGRITY_FAIL) {
> + cause = "invalid-HMAC";
> + goto out;
"modsig" is special, because having any security xattrs is not
required. This test doesn't prevent status from being set to
"missing-HMAC". This test is redundant with the original tests below.
> + } else if (status != INTEGRITY_PASS && status != INTEGRITY_UNKNOWN) {
> if ((status == INTEGRITY_NOLABEL)
> || (status == INTEGRITY_NOXATTRS))
> cause = "missing-HMAC";
> @@ -281,6 +319,43 @@ int ima_appraise_measurement(enum ima_hooks func,
> status = INTEGRITY_PASS;
> }
Calling evm_verifyxattr() with the IMA xattr value prevents EVM from
having to re-read the IMA xattr, but isn't necessary. On modsig
signature verification failure, calling evm_verifyxattr() a second
time isn't necessary.
> break;
> + case IMA_MODSIG:
> + /*
> + * To avoid being tricked into recursion, we don't allow a
> + * modsig stored in the xattr.
> + */
> + if (!appraising_modsig) {
> + status = INTEGRITY_UNKNOWN;
> + cause = "unknown-ima-data";
> +
> + break;
> + }
> +
> + rc = ima_modsig_verify(INTEGRITY_KEYRING_IMA, xattr_value);
> + if (!rc) {
> + iint->flags |= IMA_DIGSIG;
> + status =
> +
> + kfree(*xattr_value_);
> + *xattr_value_ = xattr_value;
> + *xattr_len_ = xattr_len;
> +
> + break;
> + }
When including the appended signature in the measurement list, the
corresponding file hash needs to be included in the measurement list,
which might be different than the previously calculated file hash
based on the hash algorithm as defined in the IMA xattr.
Including the file hash and signature in the measurement list allows
the attestation server, with just a public key, to verify the file
signature against the file hash. No need for a white list.
ima_modsig_verify() must calculate the file hash in order to verify
the file signature. This file hash value somehow needs to be returned
in order for it to be included in the measurement list.
> + /*
> + * The appended signature failed verification. Let's try
> + * reading a signature from the extended attribute instead.
> + */
> +
> + pr_debug("modsig didn't verify, trying the xattr signature\n");
> +
> + ima_free_xattr_data(xattr_value);
> + iint->flags &= ~IMA_MODSIG_ALLOWED;
> +
> + return ima_appraise_measurement(func, iint, file, buf, size,
> + filename, xattr_value_,
> + xattr_len_, opened);
Most of the code before "switch" needs to be done only once. Is
recursion necessary? Or can we just retry the "switch" using the IMA
xattr, assuming there is an IMA xattr?
Mimi
> default:
> status = INTEGRITY_UNKNOWN;
> cause = "unknown-ima-data";
> @@ -291,13 +366,15 @@ int ima_appraise_measurement(enum ima_hooks func,
> if (status != INTEGRITY_PASS) {
> if ((ima_appraise & IMA_APPRAISE_FIX) &&
> (!xattr_value ||
> - xattr_value->type != EVM_IMA_XATTR_DIGSIG)) {
> + (xattr_value->type != EVM_IMA_XATTR_DIGSIG &&
> + xattr_value->type != IMA_MODSIG))) {
> if (!ima_fix_xattr(dentry, iint))
> status = INTEGRITY_PASS;
> } else if ((inode->i_size == 0) &&
> (iint->flags & IMA_NEW_FILE) &&
> (xattr_value &&
> - xattr_value->type == EVM_IMA_XATTR_DIGSIG)) {
> + (xattr_value->type == EVM_IMA_XATTR_DIGSIG ||
> + xattr_value->type == IMA_MODSIG))) {
> status = INTEGRITY_PASS;
> }
> integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
> @@ -398,6 +475,7 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
> const void *xattr_value, size_t xattr_value_len)
> {
> const struct evm_ima_xattr_data *xvalue = xattr_value;
> + bool digsig;
> int result;
>
> result = ima_protect_xattr(dentry, xattr_name, xattr_value,
> @@ -405,8 +483,10 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
> if (result == 1) {
> if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
> return -EINVAL;
> - ima_reset_appraise_flags(d_backing_inode(dentry),
> - (xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0);
> +
> + digsig = xvalue->type == EVM_IMA_XATTR_DIGSIG ||
> + xvalue->type == IMA_MODSIG;
> + ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
> result = 0;
> }
> return result;
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 0b4845e7248d..93fa257c71a7 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -245,8 +245,9 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
> pathname = ima_d_path(&file->f_path, &pathbuf, filename);
>
> if (action & IMA_APPRAISE_SUBMASK)
> - rc = ima_appraise_measurement(func, iint, file, pathname,
> - xattr_value, xattr_len, opened);
> + rc = ima_appraise_measurement(func, iint, file, buf, size,
> + pathname, &xattr_value,
> + &xattr_len, opened);
> if (action & IMA_MEASURE)
> ima_store_measurement(iint, file, pathname,
> xattr_value, xattr_len, pcr);
> @@ -257,7 +258,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
> if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG) &&
> !(iint->flags & IMA_NEW_FILE))
> rc = -EACCES;
> - kfree(xattr_value);
> + ima_free_xattr_data(xattr_value);
> out_free:
> if (pathbuf)
> __putname(pathbuf);
> diff --git a/security/integrity/ima/ima_modsig.c b/security/integrity/ima/ima_modsig.c
> new file mode 100644
> index 000000000000..a74f8aa36aa7
> --- /dev/null
> +++ b/security/integrity/ima/ima_modsig.c
> @@ -0,0 +1,147 @@
> +/*
> + * IMA support for appraising module-style appended signatures.
> + *
> + * Copyright (C) 2017 IBM Corporation
> + *
> + * Author:
> + * Thiago Jung Bauermann <bau...@li...>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation (version 2 of the License).
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/types.h>
> +#include <linux/module_signature.h>
> +#include <keys/asymmetric-type.h>
> +#include <crypto/pkcs7.h>
> +
> +#include "ima.h"
> +
> +struct modsig_hdr {
> + uint8_t type; /* Should be IMA_MODSIG. */
> + const void *data; /* Pointer to data covered by pkcs7_msg. */
> + size_t data_len;
> + struct pkcs7_message *pkcs7_msg;
> + int raw_pkcs7_len;
> +
> + /* This will be in the measurement list if required by the template. */
> + struct evm_ima_xattr_data raw_pkcs7;
> +};
> +
> +/**
> + * ima_hook_supports_modsig - can the policy allow modsig for this hook?
> + *
> + * modsig is only supported by hooks using ima_post_read_file, because only they
> + * preload the contents of the file in a buffer. FILE_CHECK does that in some
> + * cases, but not when reached from vfs_open. POLICY_CHECK can support it, but
> + * it's not useful in practice because it's a text file so deny.
> + */
> +bool ima_hook_supports_modsig(enum ima_hooks func)
> +{
> + switch (func) {
> + case FIRMWARE_CHECK:
> + case KEXEC_KERNEL_CHECK:
> + case KEXEC_INITRAMFS_CHECK:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> +int ima_read_modsig(const void *buf, loff_t buf_len,
> + struct evm_ima_xattr_data **xattr_value,
> + int *xattr_len)
> +{
> + const size_t marker_len = sizeof(MODULE_SIG_STRING) - 1;
> + const struct module_signature *sig;
> + struct modsig_hdr *hdr;
> + size_t sig_len;
> + const void *p;
> + int rc;
> +
> + if (buf_len <= marker_len + sizeof(*sig))
> + return -ENOENT;
> +
> + p = buf + buf_len - marker_len;
> + if (memcmp(p, MODULE_SIG_STRING, marker_len))
> + return -ENOENT;
> +
> + buf_len -= marker_len;
> + sig = (const struct module_signature *) (p - sizeof(*sig));
> +
> + rc = validate_module_sig(sig, buf_len);
> + if (rc)
> + return rc;
> +
> + sig_len = be32_to_cpu(sig->sig_len);
> + buf_len -= sig_len + sizeof(*sig);
> +
> + hdr = kmalloc(sizeof(*hdr) + sig_len, GFP_KERNEL);
> + if (!hdr)
> + return -ENOMEM;
> +
> + hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len);
> + if (IS_ERR(hdr->pkcs7_msg)) {
> + rc = PTR_ERR(hdr->pkcs7_msg);
> + kfree(hdr);
> + return rc;
> + }
> +
> + memcpy(hdr->raw_pkcs7.data, buf + buf_len, sig_len);
> + hdr->raw_pkcs7_len = sig_len + 1;
> + hdr->raw_pkcs7.type = IMA_MODSIG;
> +
> + hdr->type = IMA_MODSIG;
> + hdr->data = buf;
> + hdr->data_len = buf_len;
> +
> + *xattr_value = (typeof(*xattr_value)) hdr;
> + *xattr_len = sizeof(*hdr);
> +
> + return 0;
> +}
> +
> +int ima_modsig_serialize_data(struct evm_ima_xattr_data *hdr,
> + struct evm_ima_xattr_data **data, int *data_len)
> +{
> + struct modsig_hdr *modsig = (struct modsig_hdr *) hdr;
> +
> + *data = &modsig->raw_pkcs7;
> + *data_len = modsig->raw_pkcs7_len;
> +
> + return 0;
> +}
> +
> +int ima_modsig_verify(const unsigned int keyring_id,
> + struct evm_ima_xattr_data *hdr)
> +{
> + struct modsig_hdr *modsig = (struct modsig_hdr *) hdr;
> + struct key *trusted_keys = integrity_keyring_from_id(keyring_id);
> +
> + if (IS_ERR(trusted_keys))
> + return -EINVAL;
> +
> + return verify_pkcs7_message_sig(modsig->data, modsig->data_len,
> + modsig->pkcs7_msg, trusted_keys,
> + VERIFYING_MODULE_SIGNATURE, NULL, NULL);
> +}
> +
> +void ima_free_xattr_data(struct evm_ima_xattr_data *hdr)
> +{
> + if (!hdr)
> + return;
> +
> + if (hdr->type == IMA_MODSIG) {
> + struct modsig_hdr *modsig = (struct modsig_hdr *) hdr;
> +
> + pkcs7_free_message(modsig->pkcs7_msg);
> + }
> +
> + kfree(hdr);
> +}
> diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
> index f4436626ccb7..4047ccabcbbf 100644
> --- a/security/integrity/ima/ima_policy.c
> +++ b/security/integrity/ima/ima_policy.c
> @@ -853,8 +853,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
> }
>
> ima_log_string(ab, "appraise_type", args[0].from);
> - if ((strcmp(args[0].from, "imasig")) == 0)
> + if (strcmp(args[0].from, "imasig") == 0)
> entry->flags |= IMA_DIGSIG_REQUIRED;
> + else if (ima_hook_supports_modsig(entry->func) &&
> + strcmp(args[0].from, "modsig|imasig") == 0)
> + entry->flags |= IMA_DIGSIG_REQUIRED
> + | IMA_MODSIG_ALLOWED;
> else
> result = -EINVAL;
> break;
> @@ -960,6 +964,12 @@ void ima_delete_rules(void)
> }
> }
>
> +#define __ima_hook_stringify(str) (#str),
> +
> +const char *const func_tokens[] = {
> + __ima_hooks(__ima_hook_stringify)
> +};
> +
> #ifdef CONFIG_IMA_READ_POLICY
> enum {
> mask_exec = 0, mask_write, mask_read, mask_append
> @@ -972,12 +982,6 @@ static const char *const mask_tokens[] = {
> "MAY_APPEND"
> };
>
> -#define __ima_hook_stringify(str) (#str),
> -
> -static const char *const func_tokens[] = {
> - __ima_hooks(__ima_hook_stringify)
> -};
> -
> void *ima_policy_start(struct seq_file *m, loff_t *pos)
> {
> loff_t l = *pos;
> @@ -1140,8 +1144,12 @@ int ima_policy_show(struct seq_file *m, void *v)
> }
> }
> }
> - if (entry->flags & IMA_DIGSIG_REQUIRED)
> - seq_puts(m, "appraise_type=imasig ");
> + if (entry->flags & IMA_DIGSIG_REQUIRED) {
> + if (entry->flags & IMA_MODSIG_ALLOWED)
> + seq_puts(m, "appraise_type=modsig|imasig ");
> + else
> + seq_puts(m, "appraise_type=imasig ");
> + }
> if (entry->flags & IMA_PERMIT_DIRECTIO)
> seq_puts(m, "permit_directio ");
> rcu_read_unlock();
> diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
> index 28af43f63572..8c7fa52604a5 100644
> --- a/security/integrity/ima/ima_template_lib.c
> +++ b/security/integrity/ima/ima_template_lib.c
> @@ -383,9 +383,21 @@ int ima_eventsig_init(struct ima_event_data *event_data,
> int xattr_len = event_data->xattr_len;
> int rc = 0;
>
> - if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG))
> + if (!xattr_value || (xattr_value->type != EVM_IMA_XATTR_DIGSIG &&
> + xattr_value->type != IMA_MODSIG))
> goto out;
>
> + /*
> + * The xattr_value for IMA_MODSIG is a runtime structure containing
> + * pointers. Get its raw data instead.
> + */
> + if (xattr_value->type == IMA_MODSIG) {
> + rc = ima_modsig_serialize_data(xattr_value, &xattr_value,
> + &xattr_len);
> + if (rc)
> + goto out;
> + }
> +
> rc = ima_write_template_field_data(xattr_value, xattr_len, fmt,
> field_data);
> out:
> diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
> index ba5f13f94ed3..2c9393cf2860 100644
> --- a/security/integrity/integrity.h
> +++ b/security/integrity/integrity.h
> @@ -28,11 +28,12 @@
>
> /* iint cache flags */
> #define IMA_ACTION_FLAGS 0xff000000
> -#define IMA_ACTION_RULE_FLAGS 0x06000000
> +#define IMA_ACTION_RULE_FLAGS 0x16000000
> #define IMA_DIGSIG 0x01000000
> #define IMA_DIGSIG_REQUIRED 0x02000000
> #define IMA_PERMIT_DIRECTIO 0x04000000
> #define IMA_NEW_FILE 0x08000000
> +#define IMA_MODSIG_ALLOWED 0x10000000
>
> #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
> IMA_APPRAISE_SUBMASK)
> @@ -58,6 +59,7 @@ enum evm_ima_xattr_type {
> EVM_XATTR_HMAC,
> EVM_IMA_XATTR_DIGSIG,
> IMA_XATTR_DIGEST_NG,
> + IMA_MODSIG,
> IMA_XATTR_LAST
> };
>
|
|
From: <817...@qq...> - 2017-07-30 07:52:13
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML><HEAD> <META content="text/html; charset=UTF-8" http-equiv=content-type> <META name=GENERATOR content="MSHTML 8.00.7601.18934"></HEAD> <BODY> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Dear Sir,</SPAN><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">How are you? We </SPAN><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">have:</SPAN><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Minilab accessories:</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">Noritsu QSS3201 calibration plate</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"> US$350/PC</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">Noritsu QSS3001 calibration plate</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"> US$350/PC</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: 宋体; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-shading: rgb(255,255,255)">Noritsu QSS3301/3302/3501 arm unit d004876 US$125/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: 宋体; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"><o:p> </o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">AOM driver Noritsu</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"> US$385/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">AOM driver Fuji </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"> US$400PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Noritsu laser gun USD1400/PC </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Fuji minilab laser gun USD1500/PC </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15>Fuji 550/570 ribbon US$16/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15>Fuji 330/340/350/355/370/375/390/395 ribbon US$14/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15>Noritsu ribbon US$15/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Doli </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">13Y/13U(45g/55g)</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"> LCD driver USD850/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">Fuji 500/550/570 minilab power supply PS1 US$1000/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">Fuji 500/550/570 minilab power supply PS2 US$800/PC</SPAN></I></B><SPAN style="FONT-FAMILY: Arial; COLOR: rgb(51,51,51); FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p></o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Crossover roller for QSS3001 US$50/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Crossover roller for QSS3201 US$55/PC </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Squeeze roller for QSS26/30 US$85/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Squeeze roller for QSS29/32/37</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: 宋体; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"> US$100PC</SPAN></I></B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></I></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">We sell</SPAN><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"> </SPAN></B><B><SPAN style="FONT-FAMILY: Arial; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">minilab accessories and spare parts</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"> for Fuji /Noritsu /Konica /Doli</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></B></P> <P style="MARGIN: 0pt" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt">We mainly deal with:</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p></o:p></SPAN></B></P> <P style="MARGIN: 0pt" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p> </o:p></SPAN></B></P> <P style="MARGIN: 0pt" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"> 1. Noritsu & Fuji laser gun and aom driver</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p></o:p></SPAN></B></P> <P style="MARGIN: 0pt" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"> 2. original,China made & used minilab spare parts</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p></o:p></SPAN></B></P> <P style="MARGIN: 0pt" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"> 3. minilab accessories and minilab necessities</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p></o:p></SPAN></B></P> <P style="MARGIN: 0pt" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"> 4. repair service, such as minilab laser, aom,PCB, power supply etc.</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">Please contact us for more info.</SPAN><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Best regards,</SPAN><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Linna</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Nanning Ida Electronic Tech Limited</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Skype: idaminilab</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Mob: 86 18376713855</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Wechat: idaminilab / 8618376713855</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></P> <P style="MARGIN: 0pt" class=MsoNormal><SPAN style="FONT-FAMILY: 'Times New Roman'; FONT-SIZE: 10.5pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p> </o:p></SPAN></P><!--EndFragment--></BODY></HTML> |
|
From: <817...@qq...> - 2017-07-30 06:04:48
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML><HEAD> <META content="text/html; charset=UTF-8" http-equiv=content-type> <META name=GENERATOR content="MSHTML 8.00.7601.18934"></HEAD> <BODY> <P style="MARGIN: 0pt" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt">Dear Sir /Madam,</SPAN><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></P> <P style="MARGIN: 0pt" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p> </o:p></SPAN></P> <P style="MARGIN: 0pt" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; COLOR: rgb(0,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">We are professional exporter of minilab machine, minilab accessories,minilab necessities and spare parts in China.</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; COLOR: rgb(0,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="MARGIN: 0pt" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; COLOR: rgb(0,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></B></P> <P style="MARGIN: 0pt" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt">We already have customers in more than 1</SPAN><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">2</SPAN><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt">0 countries in the world. We are looking for wholesaler for minilab ribbon and aom driver,</SPAN><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"> m</SPAN><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt">eanwhile, we also offer spare parts for minilabs:</SPAN><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p></o:p></SPAN></P> <P style="MARGIN: 0pt" class=MsoNormal><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"><o:p> </o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">Noritsu QSS3201 calibration plate</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"> US$350/PC</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial">Noritsu QSS3001 calibration plate</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"> US$350/PC</SPAN></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: 宋体; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-shading: rgb(255,255,255)">Noritsu QSS3301/3302/3501 arm unit d004876 US$125/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: 宋体; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="MARGIN: 0pt" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p> </o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">AOM driver Noritsu</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"> US$385/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">AOM driver Fuji </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"> US$400PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Noritsu laser gun USD1400/PC </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Fuji minilab laser gun USD1500/PC </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15>Fuji 550/570 ribbon US$16/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15>Fuji 330/340/350/355/370/375/390/395 ribbon US$14/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15>Noritsu ribbon US$15/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Doli </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">13Y/13U(45g/55g)</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"> LCD driver USD850/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">Fuji 500/550/570 minilab power supply PS1 US$1000/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">Fuji 500/550/570 minilab power supply PS2 US$800/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">Fuji 55/570 minilab dryer belt </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15> US$350/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">31K1111400 US$12/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">Ring Rubber 334F0258 US$0.5/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">Konica R1 R2 filter US$2.5/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="MARGIN: 0pt" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; COLOR: rgb(51,51,51); FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p> </o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">A070919</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15> </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: 宋体; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial; mso-shading: rgb(255,255,255)" class=15> </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15>US$35/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">turn belt for Noritsu LPS PRO USD100/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Lower turn belt for QSS2301/2611 USD25/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Crossover roller for QSS3001 US$50/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Crossover roller for QSS3201 US$55/PC </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Squeeze roller for QSS26/30 US$85/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Squeeze roller for QSS29/32/37</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: 宋体; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-bidi-font-family: Arial"> US$100PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="MARGIN: 0pt" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p> </o:p></SPAN></P> <P style="MARGIN: 0pt" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt">Any questions please feel free to let me know.</SPAN><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p></o:p></SPAN></P> <P style="MARGIN: 0pt" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p> </o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Linna</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Nanning Ida Electronic Tech Limited</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Skype: idaminilab</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Mob: 86 18376713855</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt">Wechat: idaminilab / 8618376713855</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></B></P> <P style="MARGIN: 0pt" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p> </o:p></SPAN></P> <P style="MARGIN: 0pt" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt"><o:p> </o:p></SPAN></P><!--EndFragment--></BODY></HTML> |
|
From: <817...@qq...> - 2017-07-30 02:36:41
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML><HEAD> <META content="text/html; charset=UTF-8" http-equiv=content-type> <META name=GENERATOR content="MSHTML 8.00.7601.18934"></HEAD> <BODY> <P style="TEXT-ALIGN: left; MARGIN: 5pt 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Dear Sir,</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 5pt 0pt; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Please kindly note that we can provide you the best price for the minilab items, if you are interested in, please kindly advice, then we will send you detailed information by return. </SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial">Noritsu QSS3201 calibration plate</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial"> US$350/PC</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial">Noritsu QSS3001 calibration plate</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial"> US$350/PC</SPAN></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,128,0); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: 宋体; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-shading: rgb(255,255,255)">Noritsu QSS3301/3302/3501 arm unit d004876 US$125/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: 宋体; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: 宋体; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-shading: rgb(255,255,255)"><o:p> </o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">Fuji 500/550/570 minilab power supply PS1 US$1000/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">Fuji 500/550/570 minilab power supply PS2 US$800/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">Fuji 55/570 minilab dryer belt </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15> US$350/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">31K1111400 US$12/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">Ring Rubber 334F0258 US$0.5/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,0,204); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p> </o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">AOM driver Noritsu</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"> US$385/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">AOM driver Fuji </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"> US$400PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Noritsu laser gun USD1400/PC </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Fuji minilab laser gun USD1500/PC </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15>Fuji 550/570 ribbon US$16/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15>Fuji 330/340/350/355/370/375/390/395 ribbon US$14/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15>Noritsu ribbon US$15/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Doli </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">13Y/13U(45g/55g)</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"> LCD driver USD850/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(255,0,255); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="MARGIN: 0pt" class=MsoNormal><SPAN style="FONT-FAMILY: Arial; COLOR: rgb(51,51,51); FONT-SIZE: 12pt; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt"><o:p> </o:p></SPAN></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)">A070919</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15> </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: 宋体; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial; mso-shading: rgb(255,255,255)" class=15> </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-shading: rgb(255,255,255)" class=15>US$35/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; BACKGROUND: rgb(255,255,255); COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt; mso-shading: rgb(255,255,255)"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">turn belt for Noritsu LPS PRO USD100/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Lower turn belt for QSS2301/2611 USD25/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Crossover roller for QSS3001 US$50/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Crossover roller for QSS3201 US$55/PC </SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Squeeze roller for QSS26/30 US$85/PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Squeeze roller for QSS29/32/37</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: 宋体; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 0.0000pt; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial"> US$100PC</SPAN></I></B><B><I><SPAN style="FONT-STYLE: italic; FONT-FAMILY: Arial; COLOR: rgb(0,176,80); FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></I></B></P> <P style="MARGIN: 0pt" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt"><o:p> </o:p></SPAN></B></P> <P style="MARGIN: 0pt" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt"><o:p> </o:p></SPAN></B></P> <P style="MARGIN: 0pt" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt">With 1</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial">2</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt"> years for exporting used minilab,minilab accessories,minilab parts,photoshop necessities,</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial">printer ribbon, </SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt">our products are hot selling in 1</SPAN></B><B><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-font-kerning: 1.0000pt; mso-bidi-font-family: Arial; mso-ascii-font-family: Arial; mso-hansi-font-family: Arial">20 </SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt">countries in the world. We are able to supply you quality goods and excellent service. </SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt"><o:p></o:p></SPAN></B></P> <P style="MARGIN: 0pt" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt"><o:p> </o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Linna</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Nanning Ida Electronic Tech Limited</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Skype: idaminilab</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Mob: 86 18376713855</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="TEXT-ALIGN: left; MARGIN: 0pt; mso-pagination: widow-orphan" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt">Wechat: idaminilab / 8618376713855</SPAN></B><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 0.0000pt"><o:p></o:p></SPAN></B></P> <P style="MARGIN: 0pt" class=MsoNormal><B><SPAN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt; FONT-WEIGHT: bold; mso-spacerun: 'yes'; mso-fareast-font-family: 宋体; mso-font-kerning: 1.0000pt"><o:p> </o:p></SPAN></B></P><!--EndFragment--></BODY></HTML> |
|
From: Mimi Z. <zo...@li...> - 2017-07-30 01:55:43
|
On Fri, 2017-07-28 at 17:11 -0400, Ken Goldman wrote:
> On 7/17/2017 7:26 PM, Mehmet Kayaalp wrote:
> >
> >>
> >> Question: What is the maximum number of event records?
> >
> > There is no limit and the number is stored in a long field.
>
> 1 - Long is platform dependent, right?
>
> 2 - If an attacker sends a long with 0xffffffff records, or 0xfffffff
> ffffffff records, the server should not blindly try to malloc that much
> memory.
Based on policy, files are measured and appended to the tail of the
measurement list. From a design perspective of measure before use,
the number of elements in the measurement list can not be limited. At
some point we might want to add support for saving the measurements
offline.
> >> This is a 4-byte integer representing the length of the Template Name field.
> >>
> >> Question: What is the maximum length?
> >
> > in security/integrity/ima/ima_template.c
> > #define MAX_TEMPLATE_NAME_LEN 15
>
> I'm looking for a guaranteed maximum. I don't want a server to break
> if the client side code changes.
As new template fields are defined, the maximum custom template name
length will change. The template data is prefixed with a length.
Unknown template records can be skipped. Template field data is
prefixed with a length. Unknown fields can be ignored/skipped.
>
> >> 3.4.1. Signature Type
> >>
> >> This is a 1-byte field. The value is 0x03.
> >>
> >> Question: What are the valid values and meanings. How does the type affect the other fields.
> >
> > The whole signature data is part of the xattr data. This is actually
> > not the signature type, but the xattr type defined in:
> > security/integrity/integrity.h as:
> >
> > enum evm_ima_xattr_type {
> > IMA_XATTR_DIGEST = 0x01,
> > EVM_XATTR_HMAC,
> > EVM_IMA_XATTR_DIGSIG,
> > IMA_XATTR_DIGEST_NG,
> > IMA_XATTR_LAST
> > };
> >
> > So the only value is 3 for an event with signature.
>
> I'm looking for a definition of 0x03, as well as any other values a
> server might receive.
The last field of the ima-sig ("d-ng|n-ng|sig") template includes the
file signature (0x03) in the measurement list. When Thiago
Bauermann's "Appended signatures support for IMA appraisal" patch set
is upstreamed, it will introduce a new signature format named
IMA_MOD_SIG (0x05).
Mimi
> >
> >> 3.4.2. Signature Version
> >>
> >> This is a 1-byte field. The value is 0x02.
> >>
> >> Question: What are the valid values and meanings. How does the version affect the other fields.
> >
> > Only 1 and 2 are valid right now. In function integrity_digsig_verify:
>
> What are the meanings of 1 and 2 - something I could add to the
> specification.
>
> >> 3.4.5. Signature Size
> >>
> >> This is a 2-byte integer representing the size of the Signature field.
> >>
> >> Question: What are the legal values? 1024 and 2048? Others?
> >
> > This one is defined by the signature. For RSA, the key determines the
> > resulting signature size. When writing the xattr, it is set to the return value
> > of RSA_private_encrypt:
>
> Understood, but what are the legal sizes that a server must handle.
|
|
From: Fabio V. S. <fab...@st...> - 2017-07-29 08:50:54
|
Hi all,
I'm a master student in computer engineering at politecnico di torino.
I'm doing my thesis on Remote Attestation for lightVM (especially for
docker). During the development of my project I had the need to disable
the two caches of Ima (the one looking the inode and the hashtable
lookup), in order to have the file measured every time it is loaded (in
my case this is useful because the same file can be loaded in different
containers).
I think that this feature can be useful also to other people so here is
the patch (developed and tested on the latest version of the source
code, i.e. v4.13 rc2):
From 1834f3d14cc94c1bd01999438f7ba0c0d3c9f717 Mon Sep 17 00:00:00 2001
From: Fabio Vallone <fab...@st...>
Date: Sat, 29 Jul 2017 10:01:01 +0200
Subject: [PATCH] Kernel boot parameters to disable ima caches
Signed-off-by: Fabio Vallone <fab...@st...>
---
security/integrity/ima/ima.h | 2 ++
security/integrity/ima/ima_init.c | 26 ++++++++++++++++++++++++++
security/integrity/ima/ima_main.c | 8 ++++++++
security/integrity/ima/ima_queue.c | 2 +-
4 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index d52b487..2e969b2 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -57,6 +57,8 @@ extern int ima_initialized;
extern int ima_used_chip;
extern int ima_hash_algo;
extern int ima_appraise;
+extern int ima_cache1_enabled;
+extern int ima_cache2_enabled;
/* IMA event related data */
struct ima_event_data {
diff --git a/security/integrity/ima/ima_init.c
b/security/integrity/ima/ima_init.c
index 2967d49..ce5d7d8 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -139,3 +139,29 @@ int __init ima_init(void)
return ima_fs_init();
}
+// Disable cache 1 and cache 2
+static int __init ima_cache1_setup(char *str)
+{
+ if(strncmp(str, "false", 5)==0){
+ printk("Disabling Cache1");
+ ima_cache1_enabled = 0;
+ }else{
+ ima_cache1_enabled = 1;
+ }
+
+ return 1;
+}
+__setup("ima_cache1=", ima_cache1_setup);
+
+static int __init ima_cache2_setup(char *str)
+{
+ if(strncmp(str, "false", 5)==0){
+ printk("Disabling Cache2");
+ ima_cache2_enabled = 0;
+ }else{
+ ima_cache1_enabled = 1;
+ }
+
+ return 1;
+}
+__setup("ima_cache2=", ima_cache2_setup);
diff --git a/security/integrity/ima/ima_main.c
b/security/integrity/ima/ima_main.c
index 2aebb79..be5dff0 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -28,6 +28,9 @@
#include "ima.h"
int ima_initialized;
+int ima_cache1_enabled = 1;
+int ima_cache2_enabled = 1;
+
#ifdef CONFIG_IMA_APPRAISE
int ima_appraise = IMA_APPRAISE_ENFORCE;
@@ -253,6 +256,11 @@ static int process_measurement(struct file *file,
char *buf, loff_t size,
if (action & IMA_AUDIT)
ima_audit_measurement(iint, pathname);
+ //Flush Inode For next Measurement if cache1 is disabled
+ if(ima_cache1_enabled == 0)
+ iint->measured_pcrs = 0;
+
+
out_digsig:
if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG) &&
!(iint->flags & IMA_NEW_FILE))
diff --git a/security/integrity/ima/ima_queue.c
b/security/integrity/ima/ima_queue.c
index a02a86d..7105587 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -172,7 +172,7 @@ int ima_add_template_entry(struct ima_template_entry
*entry, int violation,
mutex_lock(&ima_extend_list_mutex);
if (!violation) {
memcpy(digest, entry->digest, sizeof(digest));
- if (ima_lookup_digest_entry(digest, entry->pcr)) {
+ if (ima_cache2_enabled==1 && ima_lookup_digest_entry(digest,
entry->pcr)) {
audit_cause = "hash_exists";
result = -EEXIST;
goto out;
--
2.7.4
What I've done is the addition of two kernel boot parameters, named
'ima_cache1' and 'ima_cache2' that once setted to 'false' will disable
the two caches.
ima_cache1 force the file to be remeasured every time by setting the
inode->measured_pcrs value to 0, instead ima_cache2 will skip the lookup
on the hashtable of the cache.
If this parameter are not set or they are set to an incorrect value, ima
will continue to work exactly like now.
Do you think that this can be a nice to have into the kernel?
Best regards,
Fabio
|
|
From: Ken G. <kg...@li...> - 2017-07-28 21:11:41
|
On 7/17/2017 7:26 PM, Mehmet Kayaalp wrote:
>
>>
>> Question: What is the maximum number of event records?
>
> There is no limit and the number is stored in a long field.
1 - Long is platform dependent, right?
2 - If an attacker sends a long with 0xffffffff records, or 0xfffffff
ffffffff records, the server should not blindly try to malloc that much
memory.
>> This is a 4-byte integer representing the length of the Template Name field.
>>
>> Question: What is the maximum length?
>
> in security/integrity/ima/ima_template.c
> #define MAX_TEMPLATE_NAME_LEN 15
I'm looking for a guaranteed maximum. I don't want a server to break
if the client side code changes.
>> 3.4.1. Signature Type
>>
>> This is a 1-byte field. The value is 0x03.
>>
>> Question: What are the valid values and meanings. How does the type affect the other fields.
>
> The whole signature data is part of the xattr data. This is actually
> not the signature type, but the xattr type defined in:
> security/integrity/integrity.h as:
>
> enum evm_ima_xattr_type {
> IMA_XATTR_DIGEST = 0x01,
> EVM_XATTR_HMAC,
> EVM_IMA_XATTR_DIGSIG,
> IMA_XATTR_DIGEST_NG,
> IMA_XATTR_LAST
> };
>
> So the only value is 3 for an event with signature.
I'm looking for a definition of 0x03, as well as any other values a
server might receive.
>
>> 3.4.2. Signature Version
>>
>> This is a 1-byte field. The value is 0x02.
>>
>> Question: What are the valid values and meanings. How does the version affect the other fields.
>
> Only 1 and 2 are valid right now. In function integrity_digsig_verify:
What are the meanings of 1 and 2 - something I could add to the
specification.
>> 3.4.5. Signature Size
>>
>> This is a 2-byte integer representing the size of the Signature field.
>>
>> Question: What are the legal values? 1024 and 2048? Others?
>
> This one is defined by the signature. For RSA, the key determines the
> resulting signature size. When writing the xattr, it is set to the return value
> of RSA_private_encrypt:
Understood, but what are the legal sizes that a server must handle.
|
|
From: Ken G. <kg...@li...> - 2017-07-28 20:59:24
|
On 7/13/2017 4:02 AM, Yan Kun wrote: > Hi All, > > I am confused by the "ima-ng" template data , which elementes did it > contain? "sha256:[file digest][file name]" ? According to my documentation ima-ng d-ng | n-ng where d-ng hash algorithm + digest n-ng file name |
|
From: Magalhaes, G. (B. R&D-CL) <gui...@hp...> - 2017-07-28 14:28:36
|
> -----Original Message----- > From: Mehmet Kayaalp [mailto:mka...@li...] > Sent: segunda-feira, 24 de julho de 2017 16:30 > To: Magalhaes, Guilherme (Brazil R&D-CL) <gui...@hp...> > Cc: ima-devel <lin...@li...> > Subject: Re: [RFC PATCH 0/5] ima: namespacing IMA audit messages > > > > On Jul 21, 2017, at 3:44 PM, Magalhaes, Guilherme (Brazil R&D-CL) > <gui...@hp...> wrote: > > > > Mehmet, > > > >> As a result, clone() and unshare() with CLONE_NEWNS results in a new > >> mount and a new IMA namespace, while setns() called with the fd of > >> /proc/*/ns/mnt would NOT have the same result. A second setns() > >> call with the fd /proc/*/ns/ima would be required. > > If I understood correctly, a given mount namespace is always paired with a > given IMA namespace, but processes which setns() to a given mount > namespace, would need an additional step to fix the pairing. That means > when a process changes to a different mount namespace, the namespaced > IMA flags are still the flags 'controlled' by the old mount namespace until the > IMA namespace is fixed with a new setns(). It is also possible that a process > points to two completely unrelated mount and IMA namespaces. > > Yes, we would prefer a solution that does not require two synced calls > to setns. I was thinking of putting the nsproxy pointer in the nsfs > inode->i_private. So that, in setns we can get to the ima_namespace. > > > This namespaces relation might confuse the audit log since a given mount > namespace id might appear twice for the same file with no file change, or an > expected entry may be not logged since the process changed to an IMA > namespace where the inode namespaced flag was already IMA_AUDITED. > > Probably one side effect from that is in the audit log, which should be fixed > replacing 'ns_mnt' with 'ns_ima' on the audit record. > > Yes, we could have both, maybe? Right, on this case, both might be needed. -- Guilherme > > Mehmet |
|
From: Magalhaes, G. (B. R&D-CL) <gui...@hp...> - 2017-07-28 14:27:44
|
> -----Original Message----- > From: Mehmet Kayaalp [mailto:mka...@li...] > Sent: segunda-feira, 24 de julho de 2017 16:33 > To: Magalhaes, Guilherme (Brazil R&D-CL) <gui...@hp...> > Cc: Mimi Zohar <zo...@li...>; linux-ima- > de...@li... > Subject: Re: [Linux-ima-devel] [RFC 2/4] ima: use namespaced flags for > IMA_AUDITED on each namespace > > > > On Jul 21, 2017, at 3:43 PM, Magalhaes, Guilherme (Brazil R&D-CL) > <gui...@hp...> wrote: > > > > Thanks, Mehmet. > > > >> As a result, the namespace cleanup does not touch inodes or iints. > However, > >> we didn't save the inode-->namespace association, so we don't have a > way > >> of removing the flags when the inode is removed. But we keep a copy of > >> ino and generation, so if inode matches but ino and generation do not > >> match, we can reset and reuse it. > > Does it also solves the file change case? Should you add the i_version? > When a file is changed, the namespaced flags must be cleared in all > namespaces so the file can be audited again in all namespaces. The > i_version/generation checkings should be done every time the namespaced > flags are referenced and also clearing the flags if not matching, right? > > On the other hand, all these new fields consume memory which might be a > considerable amount when there are many files under many namespaces. > > Yes, adding the i_version would be necessary. You are correct. There > is a memory vs lookup/cleanup trade off here. > > >> The extra lookup is the namespace one. We should be able to tell the > >> current namespace without needing an rbtree or a hash table. > > This is a good way to avoid the need for additional 2-look ups, while it is > still not clear to me why a whole new namespace is needed and we should > think about it carefully to avoid side effects. It seems actually an extension > of mount namespace, it is like this probably related to possibilities of > upstream acceptance. I believe AppArmor tried to add a real new namespace > with a new clone() flag and it was not accepted. Any concerns with that? This > new IMA namespace could be used in the future for namespacing the policy, > while I believe the user namespace could be a better option for namespacing > the policy. > > Having explicit IMA namespacing would probably be better. I don't know > what the right way is. Having a separate clone flag would be helpful, > but I understand if one flag per each kernel feature may not be feasible. We can try to understand how AppArmor did it: http://wiki.apparmor.net/index.php/AppArmorNamespaces#AppArmor_Policy_Namespaces_Table_of_Contents -- Guilherme > > Mehmet > |