From: Shane Wang <shane.wang@intel.com>
To: "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Cc: Ingo Molnar <mingo@elte.hu>, "H. Peter Anvin" <hpa@zytor.com>,
"Cihula, Joseph" <joseph.cihula@intel.com>,
"arjan@linux.intel.com" <arjan@linux.intel.com>,
"andi@firstfloor.org" <andi@firstfloor.org>,
"chrisw@sous-sol.org" <chrisw@sous-sol.org>,
"jmorris@namei.org" <jmorris@namei.org>,
"jbeulich@novell.com" <jbeulich@novell.com>,
"peterm@redhat.com" <peterm@redhat.com>
Subject: [PATCH] intel_txt: add s3 userspace memory integrity verification
Date: Sun, 27 Sep 2009 17:07:28 +0800 [thread overview]
Message-ID: <4ABF2B50.6070106@intel.com> (raw)
In-Reply-To: <4A9CE0B2.5060608@intel.com>
[-- Attachment #1: Type: text/plain, Size: 7677 bytes --]
This patch added verification for userspace memory integrity after s3 resume.
Integrity verification for other memory (say kernel itself) has been done by tboot.
Thanks for your comments.
Shane
---
arch/x86/kernel/tboot.c | 170 ++++++++++++++++++++++++++++++++++++++
drivers/acpi/sleep.c | 4
include/linux/tboot.h | 7 +
security/Kconfig | 2
4 files changed, 182 insertions(+), 1 deletion(-)
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Joseph Cihula <joseph.cihula@intel.com>
diff -r 42870e183bd5 arch/x86/kernel/tboot.c
--- a/arch/x86/kernel/tboot.c Fri Sep 25 06:06:39 2009 -0400
+++ b/arch/x86/kernel/tboot.c Fri Sep 25 11:03:04 2009 -0400
@@ -20,6 +20,7 @@
*/
#include <linux/dma_remapping.h>
+#include <linux/scatterlist.h>
#include <linux/init_task.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
@@ -30,12 +31,17 @@
#include <linux/pfn.h>
#include <linux/mm.h>
#include <linux/tboot.h>
+#include <linux/random.h>
+
+#include <crypto/vmac.h>
+#include <crypto/hash.h>
#include <asm/trampoline.h>
#include <asm/processor.h>
#include <asm/bootparam.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
+#include <asm/percpu.h>
#include <asm/fixmap.h>
#include <asm/proto.h>
#include <asm/setup.h>
@@ -168,6 +174,80 @@ static void tboot_create_trampoline(void
map_base, map_size);
}
+static vmac_t mem_mac;
+static struct crypto_hash *tfm;
+
+static int tboot_gen_mem_integrity(const uint8_t key[], vmac_t *mac)
+{
+ int i, j, ret;
+ pg_data_t *pgdat;
+ struct hash_desc desc;
+ struct scatterlist sg[1];
+ struct page *page;
+ uint64_t paddr, rstart, rend;
+ unsigned long pfn;
+ uint8_t zeroed_key[VMAC_KEY_LEN];
+
+ if (!tfm)
+ tfm = crypto_alloc_hash("vmac(aes)", 0, CRYPTO_ALG_ASYNC);
+
+ if (IS_ERR(tfm)) {
+ tfm = NULL;
+ return -ENOMEM;
+ }
+
+ desc.tfm = tfm;
+ desc.flags = 0;
+
+ sg_init_table(sg, 1);
+
+ ret = crypto_hash_init(&desc);
+ if (ret)
+ return ret;
+ ret = crypto_hash_setkey(desc.tfm, key, VMAC_KEY_LEN);
+ if (ret)
+ return ret;
+
+ for_each_online_pgdat(pgdat) {
+ for (i = 0, pfn = pgdat->node_start_pfn;
+ i < pgdat->node_spanned_pages;
+ i++, pfn = pgdat->node_start_pfn + i) {
+
+ if (!pfn_valid(pfn) || !page_is_ram(pfn))
+ continue;
+
+ page = pfn_to_page(pfn);
+ paddr = page_to_phys(page);
+
+ /* If pg will be MACed by tboot, no need to MAC here */
+ for (j = 0; j < tboot->num_mac_regions; j++) {
+ rstart = tboot->mac_regions[j].start;
+ rend = rstart + tboot->mac_regions[j].size;
+ if (((paddr + PAGE_SIZE) <= rstart)
+ || (rend <= paddr))
+ continue;
+ break;
+ }
+
+ if (j == tboot->num_mac_regions) {
+ sg_set_page(sg, page, PAGE_SIZE, 0);
+ ret = crypto_hash_update(&desc, sg, PAGE_SIZE);
+ if (ret)
+ return ret;
+ }
+ }
+ }
+ ret = crypto_hash_final(&desc, (uint8_t *)mac);
+ if (ret)
+ return ret;
+
+ /* Clean the key */
+ memset(zeroed_key, 0, sizeof(zeroed_key));
+ crypto_hash_setkey(desc.tfm, zeroed_key, VMAC_KEY_LEN);
+
+ return 0;
+}
+
#ifdef CONFIG_ACPI_SLEEP
static void add_mac_region(phys_addr_t start, unsigned long size)
@@ -197,6 +277,16 @@ static int tboot_setup_sleep(void)
/* kernel code + data + bss */
add_mac_region(virt_to_phys(_text), _end - _text);
+ /* stack */
+ add_mac_region(virt_to_phys(current_thread_info()), THREAD_SIZE);
+
+ /* MAC userspace memory not handled by tboot */
+ get_random_bytes(tboot->s3_key, sizeof(tboot->s3_key));
+ if (tboot_gen_mem_integrity(tboot->s3_key, &mem_mac)) {
+ panic("tboot: vmac generation failed\n");
+ return -1;
+ }
+
tboot->acpi_sinfo.kernel_s3_resume_vector = acpi_wakeup_address;
return 0;
@@ -212,6 +302,68 @@ static int tboot_setup_sleep(void)
}
#endif
+
+static struct thread_info *low_ti, *current_ti;
+
+static void tboot_do_stack_switch(struct thread_info *new_ti,
+ struct thread_info *old_ti)
+{
+ memcpy(new_ti, old_ti, THREAD_SIZE);
+#ifdef CONFIG_X86_32
+ asm volatile (
+ " and %0, %%esp; "
+ " add %1, %%esp; "
+ : : "i" (THREAD_SIZE - 1), "r" (new_ti));
+#else
+ asm volatile (
+ " and %0, %%rsp; "
+ " add %1, %%rsp; "
+ : : "i" (THREAD_SIZE - 1), "r" (new_ti));
+ percpu_write(kernel_stack, (unsigned long)new_ti -
+ KERNEL_STACK_OFFSET + THREAD_SIZE);
+#endif
+ current->stack = new_ti;
+}
+
+void tboot_switch_stack(void)
+{
+ if (!tboot_enabled())
+ return;
+
+ current_ti = current_thread_info();
+
+ /* If thread info is above 4G, then switch stack */
+ if (!((PFN_PHYS(PFN_DOWN(virt_to_phys(current_ti)))
+ + (PFN_UP(THREAD_SIZE) << PAGE_SHIFT))
+ & 0xffffffff00000000ULL))
+ return;
+
+ if (low_ti == NULL)
+ low_ti = (struct thread_info *)
+ __get_free_pages(GFP_DMA32, THREAD_ORDER);
+
+ tboot_do_stack_switch(low_ti, current_ti);
+}
+
+void tboot_restore_stack(void)
+{
+ if (!tboot_enabled())
+ return;
+
+ if (current_ti == NULL)
+ BUG();
+
+ /* If thread info is above 4G, then restore stack */
+ if (!((PFN_PHYS(PFN_DOWN(virt_to_phys(current_ti)))
+ + (PFN_UP(THREAD_SIZE) << PAGE_SHIFT))
+ & 0xffffffff00000000ULL))
+ return;
+
+ if (low_ti == NULL)
+ BUG();
+
+ tboot_do_stack_switch(current_ti, low_ti);
+}
void tboot_shutdown(u32 shutdown_type)
{
@@ -292,6 +444,24 @@ void tboot_sleep(u8 sleep_state, u32 pm1
}
tboot_shutdown(acpi_shutdown_map[sleep_state]);
+}
+
+void tboot_sx_resume(void)
+{
+ vmac_t mac;
+
+ if (!tboot_enabled())
+ return;
+
+ if (tboot_gen_mem_integrity(tboot->s3_key, &mac))
+ panic("tboot: vmac generation failed\n");
+ else if (mac != mem_mac)
+ panic("tboot: memory integrity was lost on resume\n");
+ else
+ pr_info("memory integrity OK\n");
+
+ /* Clean s3_key */
+ memset(tboot->s3_key, 0, sizeof(tboot->s3_key));
}
static atomic_t ap_wfs_count;
diff -r 42870e183bd5 drivers/acpi/sleep.c
--- a/drivers/acpi/sleep.c Fri Sep 25 06:06:39 2009 -0400
+++ b/drivers/acpi/sleep.c Fri Sep 25 11:03:04 2009 -0400
@@ -16,6 +16,7 @@
#include <linux/device.h>
#include <linux/suspend.h>
#include <linux/reboot.h>
+#include <linux/tboot.h>
#include <asm/io.h>
@@ -244,7 +245,10 @@ static int acpi_suspend_enter(suspend_st
break;
case ACPI_STATE_S3:
+ tboot_switch_stack();
do_suspend_lowlevel();
+ tboot_sx_resume();
+ tboot_restore_stack();
break;
}
diff -r 42870e183bd5 include/linux/tboot.h
--- a/include/linux/tboot.h Fri Sep 25 06:06:39 2009 -0400
+++ b/include/linux/tboot.h Fri Sep 25 11:03:04 2009 -0400
@@ -147,7 +147,9 @@ extern struct acpi_table_header *tboot_g
extern struct acpi_table_header *tboot_get_dmar_table(
struct acpi_table_header *dmar_tbl);
extern int tboot_force_iommu(void);
-
+extern void tboot_sx_resume(void);
+extern void tboot_switch_stack(void);
+extern void tboot_restore_stack(void);
#else
#define tboot_probe() do { } while (0)
@@ -156,6 +158,9 @@ extern int tboot_force_iommu(void);
do { } while (0)
#define tboot_get_dmar_table(dmar_tbl) (dmar_tbl)
#define tboot_force_iommu() 0
+#define tboot_sx_resume() do { } while (0)
+#define tboot_switch_stack() do { } while (0)
+#define tboot_restore_stack() do { } while (0)
#endif /* !CONFIG_INTEL_TXT */
diff -r 42870e183bd5 security/Kconfig
--- a/security/Kconfig Fri Sep 25 06:06:39 2009 -0400
+++ b/security/Kconfig Fri Sep 25 11:03:04 2009 -0400
@@ -116,6 +116,8 @@ config INTEL_TXT
config INTEL_TXT
bool "Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)"
depends on HAVE_INTEL_TXT
+ select CRYPTO_VMAC
+ select CRYPTO_AES
help
This option enables support for booting the kernel with the
Trusted Boot (tboot) module. This will utilize
[-- Attachment #2: s3_integrity.patch --]
[-- Type: text/plain, Size: 7374 bytes --]
This patch added verification for userspace memory integrity after s3 resume.
Integrity verification for other memory (say kernel itself) has been done by tboot.
Signed-off-by: Shane Wang <shane.wang@intel.com>
Signed-off-by: Joseph Cihula <joseph.cihula@intel.com>
diff -r 42870e183bd5 arch/x86/kernel/tboot.c
--- a/arch/x86/kernel/tboot.c Fri Sep 25 06:06:39 2009 -0400
+++ b/arch/x86/kernel/tboot.c Fri Sep 25 11:03:04 2009 -0400
@@ -20,6 +20,7 @@
*/
#include <linux/dma_remapping.h>
+#include <linux/scatterlist.h>
#include <linux/init_task.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
@@ -30,12 +31,17 @@
#include <linux/pfn.h>
#include <linux/mm.h>
#include <linux/tboot.h>
+#include <linux/random.h>
+
+#include <crypto/vmac.h>
+#include <crypto/hash.h>
#include <asm/trampoline.h>
#include <asm/processor.h>
#include <asm/bootparam.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
+#include <asm/percpu.h>
#include <asm/fixmap.h>
#include <asm/proto.h>
#include <asm/setup.h>
@@ -168,6 +174,80 @@ static void tboot_create_trampoline(void
map_base, map_size);
}
+static vmac_t mem_mac;
+static struct crypto_hash *tfm;
+
+static int tboot_gen_mem_integrity(const uint8_t key[], vmac_t *mac)
+{
+ int i, j, ret;
+ pg_data_t *pgdat;
+ struct hash_desc desc;
+ struct scatterlist sg[1];
+ struct page *page;
+ uint64_t paddr, rstart, rend;
+ unsigned long pfn;
+ uint8_t zeroed_key[VMAC_KEY_LEN];
+
+ if (!tfm)
+ tfm = crypto_alloc_hash("vmac(aes)", 0, CRYPTO_ALG_ASYNC);
+
+ if (IS_ERR(tfm)) {
+ tfm = NULL;
+ return -ENOMEM;
+ }
+
+ desc.tfm = tfm;
+ desc.flags = 0;
+
+ sg_init_table(sg, 1);
+
+ ret = crypto_hash_init(&desc);
+ if (ret)
+ return ret;
+ ret = crypto_hash_setkey(desc.tfm, key, VMAC_KEY_LEN);
+ if (ret)
+ return ret;
+
+ for_each_online_pgdat(pgdat) {
+ for (i = 0, pfn = pgdat->node_start_pfn;
+ i < pgdat->node_spanned_pages;
+ i++, pfn = pgdat->node_start_pfn + i) {
+
+ if (!pfn_valid(pfn) || !page_is_ram(pfn))
+ continue;
+
+ page = pfn_to_page(pfn);
+ paddr = page_to_phys(page);
+
+ /* If pg will be MACed by tboot, no need to MAC here */
+ for (j = 0; j < tboot->num_mac_regions; j++) {
+ rstart = tboot->mac_regions[j].start;
+ rend = rstart + tboot->mac_regions[j].size;
+ if (((paddr + PAGE_SIZE) <= rstart)
+ || (rend <= paddr))
+ continue;
+ break;
+ }
+
+ if (j == tboot->num_mac_regions) {
+ sg_set_page(sg, page, PAGE_SIZE, 0);
+ ret = crypto_hash_update(&desc, sg, PAGE_SIZE);
+ if (ret)
+ return ret;
+ }
+ }
+ }
+ ret = crypto_hash_final(&desc, (uint8_t *)mac);
+ if (ret)
+ return ret;
+
+ /* Clean the key */
+ memset(zeroed_key, 0, sizeof(zeroed_key));
+ crypto_hash_setkey(desc.tfm, zeroed_key, VMAC_KEY_LEN);
+
+ return 0;
+}
+
#ifdef CONFIG_ACPI_SLEEP
static void add_mac_region(phys_addr_t start, unsigned long size)
@@ -197,6 +277,16 @@ static int tboot_setup_sleep(void)
/* kernel code + data + bss */
add_mac_region(virt_to_phys(_text), _end - _text);
+ /* stack */
+ add_mac_region(virt_to_phys(current_thread_info()), THREAD_SIZE);
+
+ /* MAC userspace memory not handled by tboot */
+ get_random_bytes(tboot->s3_key, sizeof(tboot->s3_key));
+ if (tboot_gen_mem_integrity(tboot->s3_key, &mem_mac)) {
+ panic("tboot: vmac generation failed\n");
+ return -1;
+ }
+
tboot->acpi_sinfo.kernel_s3_resume_vector = acpi_wakeup_address;
return 0;
@@ -212,6 +302,68 @@ static int tboot_setup_sleep(void)
}
#endif
+
+static struct thread_info *low_ti, *current_ti;
+
+static void tboot_do_stack_switch(struct thread_info *new_ti,
+ struct thread_info *old_ti)
+{
+ memcpy(new_ti, old_ti, THREAD_SIZE);
+#ifdef CONFIG_X86_32
+ asm volatile (
+ " and %0, %%esp; "
+ " add %1, %%esp; "
+ : : "i" (THREAD_SIZE - 1), "r" (new_ti));
+#else
+ asm volatile (
+ " and %0, %%rsp; "
+ " add %1, %%rsp; "
+ : : "i" (THREAD_SIZE - 1), "r" (new_ti));
+ percpu_write(kernel_stack, (unsigned long)new_ti -
+ KERNEL_STACK_OFFSET + THREAD_SIZE);
+#endif
+ current->stack = new_ti;
+}
+
+void tboot_switch_stack(void)
+{
+ if (!tboot_enabled())
+ return;
+
+ current_ti = current_thread_info();
+
+ /* If thread info is above 4G, then switch stack */
+ if (!((PFN_PHYS(PFN_DOWN(virt_to_phys(current_ti)))
+ + (PFN_UP(THREAD_SIZE) << PAGE_SHIFT))
+ & 0xffffffff00000000ULL))
+ return;
+
+ if (low_ti == NULL)
+ low_ti = (struct thread_info *)
+ __get_free_pages(GFP_DMA32, THREAD_ORDER);
+
+ tboot_do_stack_switch(low_ti, current_ti);
+}
+
+void tboot_restore_stack(void)
+{
+ if (!tboot_enabled())
+ return;
+
+ if (current_ti == NULL)
+ BUG();
+
+ /* If thread info is above 4G, then restore stack */
+ if (!((PFN_PHYS(PFN_DOWN(virt_to_phys(current_ti)))
+ + (PFN_UP(THREAD_SIZE) << PAGE_SHIFT))
+ & 0xffffffff00000000ULL))
+ return;
+
+ if (low_ti == NULL)
+ BUG();
+
+ tboot_do_stack_switch(current_ti, low_ti);
+}
void tboot_shutdown(u32 shutdown_type)
{
@@ -292,6 +444,24 @@ void tboot_sleep(u8 sleep_state, u32 pm1
}
tboot_shutdown(acpi_shutdown_map[sleep_state]);
+}
+
+void tboot_sx_resume(void)
+{
+ vmac_t mac;
+
+ if (!tboot_enabled())
+ return;
+
+ if (tboot_gen_mem_integrity(tboot->s3_key, &mac))
+ panic("tboot: vmac generation failed\n");
+ else if (mac != mem_mac)
+ panic("tboot: memory integrity was lost on resume\n");
+ else
+ pr_info("memory integrity OK\n");
+
+ /* Clean s3_key */
+ memset(tboot->s3_key, 0, sizeof(tboot->s3_key));
}
static atomic_t ap_wfs_count;
diff -r 42870e183bd5 drivers/acpi/sleep.c
--- a/drivers/acpi/sleep.c Fri Sep 25 06:06:39 2009 -0400
+++ b/drivers/acpi/sleep.c Fri Sep 25 11:03:04 2009 -0400
@@ -16,6 +16,7 @@
#include <linux/device.h>
#include <linux/suspend.h>
#include <linux/reboot.h>
+#include <linux/tboot.h>
#include <asm/io.h>
@@ -244,7 +245,10 @@ static int acpi_suspend_enter(suspend_st
break;
case ACPI_STATE_S3:
+ tboot_switch_stack();
do_suspend_lowlevel();
+ tboot_sx_resume();
+ tboot_restore_stack();
break;
}
diff -r 42870e183bd5 include/linux/tboot.h
--- a/include/linux/tboot.h Fri Sep 25 06:06:39 2009 -0400
+++ b/include/linux/tboot.h Fri Sep 25 11:03:04 2009 -0400
@@ -147,7 +147,9 @@ extern struct acpi_table_header *tboot_g
extern struct acpi_table_header *tboot_get_dmar_table(
struct acpi_table_header *dmar_tbl);
extern int tboot_force_iommu(void);
-
+extern void tboot_sx_resume(void);
+extern void tboot_switch_stack(void);
+extern void tboot_restore_stack(void);
#else
#define tboot_probe() do { } while (0)
@@ -156,6 +158,9 @@ extern int tboot_force_iommu(void);
do { } while (0)
#define tboot_get_dmar_table(dmar_tbl) (dmar_tbl)
#define tboot_force_iommu() 0
+#define tboot_sx_resume() do { } while (0)
+#define tboot_switch_stack() do { } while (0)
+#define tboot_restore_stack() do { } while (0)
#endif /* !CONFIG_INTEL_TXT */
diff -r 42870e183bd5 security/Kconfig
--- a/security/Kconfig Fri Sep 25 06:06:39 2009 -0400
+++ b/security/Kconfig Fri Sep 25 11:03:04 2009 -0400
@@ -116,6 +116,8 @@ config INTEL_TXT
config INTEL_TXT
bool "Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)"
depends on HAVE_INTEL_TXT
+ select CRYPTO_VMAC
+ select CRYPTO_AES
help
This option enables support for booting the kernel with the
Trusted Boot (tboot) module. This will utilize
next prev parent reply other threads:[~2009-09-27 9:07 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-09-01 8:52 [PATCH] intel_txt: fix the build errors of intel_txt patch on non-X86 platforms (resend) Shane Wang
2009-09-27 9:07 ` Shane Wang [this message]
2009-09-29 2:27 ` [PATCH] intel_txt: fix the buggy timeout warning logic in tboot Shane Wang
2009-10-04 18:58 ` [PATCH] intel_txt: add s3 userspace memory integrity verification Pavel Machek
2009-10-04 23:26 ` Andi Kleen
2009-10-15 7:57 ` Wang, Shane
2009-12-04 9:07 ` Wang, Shane
2009-12-04 8:19 ` Pavel Machek
2009-12-04 16:46 ` Cihula, Joseph
2009-12-04 17:13 ` Andi Kleen
2009-12-04 17:41 ` Cihula, Joseph
2009-12-04 20:09 ` Andi Kleen
2009-12-04 20:17 ` Cihula, Joseph
2009-12-04 20:31 ` Andi Kleen
2009-12-04 21:27 ` H. Peter Anvin
2009-12-04 17:53 ` H. Peter Anvin
2009-12-04 20:10 ` Andi Kleen
2009-12-04 22:25 ` Pavel Machek
2009-12-04 22:15 ` Pavel Machek
2009-12-04 22:24 ` H. Peter Anvin
2009-12-04 22:39 ` Pavel Machek
2009-12-04 22:46 ` H. Peter Anvin
2010-03-09 8:52 ` [PATCH v2] intel_txt: add support for S3 memory integrity protection within Intel(R) TXT launched kernel Wang, Shane
2010-03-09 9:06 ` Pavel Machek
2010-03-09 9:06 ` Pavel Machek
2010-03-10 6:36 ` [PATCH v3] " Shane Wang
2010-03-10 6:36 ` Shane Wang
2010-03-10 20:31 ` Rafael J. Wysocki
2010-03-10 20:31 ` Rafael J. Wysocki
2010-03-19 21:18 ` [tip:x86/txt] x86, tboot: Add support for S3 memory integrity protection tip-bot for Shane Wang
2010-03-09 8:52 ` [PATCH v2] intel_txt: add support for S3 memory integrity protection within Intel(R) TXT launched kernel Wang, Shane
-- strict thread matches above, loose matches on Subject: below --
2009-12-04 9:12 [PATCH] intel_txt: add s3 userspace memory integrity verification Shane Wang
2009-12-04 8:29 ` Pavel Machek
2009-12-04 8:29 ` Pavel Machek
2009-12-04 16:52 ` Cihula, Joseph
2009-12-04 22:20 ` Pavel Machek
2009-12-04 22:20 ` Pavel Machek
2009-12-04 16:52 ` Cihula, Joseph
2009-12-04 11:05 ` Andi Kleen
2009-12-04 11:05 ` Andi Kleen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4ABF2B50.6070106@intel.com \
--to=shane.wang@intel.com \
--cc=andi@firstfloor.org \
--cc=arjan@linux.intel.com \
--cc=chrisw@sous-sol.org \
--cc=hpa@zytor.com \
--cc=jbeulich@novell.com \
--cc=jmorris@namei.org \
--cc=joseph.cihula@intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=peterm@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.