Skip to contentSkip to conversation

x86/sgx: A collection of tests and fixes

PATCH In review Jarkko Sakkinen 4 participants 38 messages Aug 31, 2022 – Sep 4, 2022

Subsystems (4)
lore
Share & tools
lore

Jarkko Sakkinen

author maintainer
#0 lore raw

v2 cover x86/sgx: A collection of tests and fixes

Haitao Huang (2):
x86/sgx: Handle VA page allocation failure for EAUG on PF. selftests/sgx: retry the ioctls returned with EAGAIN

Jarkko Sakkinen (2):
x86/sgx: Do not consider unsanitized pages an error selftests/sgx: Add a bpftrace script for tracking allocation errors

Kristen Carlson Accardi (1):
selftests/sgx: Ignore OpenSSL 3.0 deprecated functions warning

Vijay Dhanraj (1):
selftests/sgx: Add SGX selftest augment_via_eaccept_long

 arch/x86/kernel/cpu/sgx/encl.c             |   5 +-
 arch/x86/kernel/cpu/sgx/main.c             |  42 ++++-
 tools/testing/selftests/sgx/alloc-error.bt |   9 +
 tools/testing/selftests/sgx/load.c         |   5 +-
 tools/testing/selftests/sgx/main.c         | 185 ++++++++++++++++++---
 tools/testing/selftests/sgx/main.h         |   3 +-
 tools/testing/selftests/sgx/sigstruct.c    |   6 +
 7 files changed, 218 insertions(+), 37 deletions(-)
 create mode 100644 tools/testing/selftests/sgx/alloc-error.bt
Signature · 1 line
2.37.2
author maintainer
#1 lore raw

PATCH v2 1/6 selftests/sgx: Ignore OpenSSL 3.0 deprecated functions warning

From: Kristen Carlson Accardi <[email protected]>

OpenSSL 3.0 deprecates some of the functions used in the SGX selftests, causing build errors on new distros. For now ignore the warnings until support for the functions is no longer available and mark FIXME so that it can be clear this should be removed at some point.

---
v2:
- Kept because does not exist in tip/x86/sgx, which is the maintainer branch for SGX, and is required for selftests.

---
 tools/testing/selftests/sgx/sigstruct.c | 6 ++++++
 1 file changed, 6 insertions(+)
tools/testing/selftests/sgx/sigstruct.c +6 -0
index 50c5ab1aa6fa..a07896a46364 100644
@@ -17,6 +17,12 @@
 #include "defines.h"
 #include "main.h"
 
+/*
+ * FIXME: OpenSSL 3.0 has deprecated some functions. For now just ignore
+ * the warnings.
+ */
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
 struct q1q2_ctx {
 	BN_CTX *bn_ctx;
 	BIGNUM *m;
Signature · 1 line
2.37.2
author maintainer
#2 lore raw

PATCH v2 2/6 x86/sgx: Do not consider unsanitized pages an error

In reply to Jarkko Sakkinen

In sgx_init(), if misc_register() fails or misc_register() succeeds but neither sgx_drv_init() nor sgx_vepc_init() succeeds, then ksgxd will be prematurely stopped. This may leave some unsanitized pages, which does not matter, because SGX will be disabled for the whole power cycle.

This triggers WARN_ON() because sgx_dirty_page_list ends up being non-empty, and dumps the call stack:

[    0.268103] sgx: EPC section 0x40200000-0x45f7ffff
[    0.268591] ------------[ cut here ]------------
[    0.268592] WARNING: CPU: 6 PID: 83 at
arch/x86/kernel/cpu/sgx/main.c:401 ksgxd+0x1b7/0x1d0
[    0.268598] Modules linked in:
[    0.268600] CPU: 6 PID: 83 Comm: ksgxd Not tainted 6.0.0-rc2 #382
[    0.268603] Hardware name: Dell Inc. XPS 13 9370/0RMYH9, BIOS 1.21.0
07/06/2022
[    0.268604] RIP: 0010:ksgxd+0x1b7/0x1d0
[    0.268607] Code: ff e9 f2 fe ff ff 48 89 df e8 75 07 0e 00 84 c0 0f
84 c3 fe ff ff 31 ff e8 e6 07 0e 00 84 c0 0f 85 94 fe ff ff e9 af fe ff
ff <0f> 0b e9 7f fe ff ff e8 dd 9c 95 00 66 66 2e 0f 1f 84 00 00 00 00
[    0.268608] RSP: 0000:ffffb6c7404f3ed8 EFLAGS: 00010287
[    0.268610] RAX: ffffb6c740431a10 RBX: ffff8dcd8117b400 RCX:
0000000000000000
[    0.268612] RDX: 0000000080000000 RSI: ffffb6c7404319d0 RDI:
00000000ffffffff
[    0.268613] RBP: ffff8dcd820a4d80 R08: ffff8dcd820a4180 R09:
ffff8dcd820a4180
[    0.268614] R10: 0000000000000000 R11: 0000000000000006 R12:
ffffb6c74006bce0
[    0.268615] R13: ffff8dcd80e63880 R14: ffffffffa8a60f10 R15:
0000000000000000
[    0.268616] FS:  0000000000000000(0000) GS:ffff8dcf25580000(0000)
knlGS:0000000000000000
[    0.268617] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.268619] CR2: 0000000000000000 CR3: 0000000213410001 CR4:
00000000003706e0
[    0.268620] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[    0.268621] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[    0.268622] Call Trace:
[    0.268624]  <TASK>
[    0.268627]  ? _raw_spin_lock_irqsave+0x24/0x60
[    0.268632]  ? _raw_spin_unlock_irqrestore+0x23/0x40
[    0.268634]  ? __kthread_parkme+0x36/0x90
[    0.268637]  kthread+0xe5/0x110
[    0.268639]  ? kthread_complete_and_exit+0x20/0x20
[    0.268642]  ret_from_fork+0x1f/0x30
[    0.268647]  </TASK>
[    0.268648] ---[ end trace 0000000000000000 ]---

Ultimately this can crash the kernel, if the following is set:

/proc/sys/kernel/panic_on_warn

In premature stop, print nothing, as the number is by practical means a random number. Otherwise, it is an indicator of a bug in the driver, and therefore print the number of unsanitized pages with pr_err().

Fixes 51ab30eb2ad4 ("x86/sgx: Replace section->init_laundry_list with sgx_dirty_page_list")
Cc [email protected] # v5.13+

---
v6:
- Address Reinette's feedback:
https://lore.kernel.org/linux-sgx/Yw6%2FiTzSdSw%2FY%[email protected]/

v5:
- Add the klog dump and sysctl option to the commit message.

v4:
- Explain expectations for dirty_page_list in the function header, instead of an inline comment.
- Improve commit message to explain the conditions better.
- Return the number of pages left dirty to ksgxd() and print warning after the 2nd call, if there are any.

v3:
- Remove WARN_ON().
- Tuned comments and the commit message a bit.

v2:
- Replaced WARN_ON() with optional pr_info() inside __sgx_sanitize_pages().
- Rewrote the commit message.
- Added the fixes tag.

---
 arch/x86/kernel/cpu/sgx/main.c | 42 ++++++++++++++++++++++++++++------
 1 file changed, 35 insertions(+), 7 deletions(-)
arch/x86/kernel/cpu/sgx/main.c +35 -7
index 515e2a5f25bb..bcd6b64961bd 100644
@@ -49,17 +49,20 @@ static LIST_HEAD(sgx_dirty_page_list);
  * Reset post-kexec EPC pages to the uninitialized state. The pages are removed
  * from the input list, and made available for the page allocator. SECS pages
  * prepending their children in the input list are left intact.
+ *
+ * Contents of the @dirty_page_list must be thread-local, i.e.
+ * not shared by multiple threads.
  */
-static void __sgx_sanitize_pages(struct list_head *dirty_page_list)
+static long __sgx_sanitize_pages(struct list_head *dirty_page_list)
 {
 	struct sgx_epc_page *page;
+	long left_dirty = 0;
 	LIST_HEAD(dirty);
 	int ret;
 
-	/* dirty_page_list is thread-local, no need for a lock: */
 	while (!list_empty(dirty_page_list)) {
 		if (kthread_should_stop())
-			return;
+			return -ECANCELED;
 
 		page = list_first_entry(dirty_page_list, struct sgx_epc_page, list);
 
@@ -92,12 +95,14 @@ static void __sgx_sanitize_pages(struct list_head *dirty_page_list)
 		} else {
 			/* The page is not yet clean - move to the dirty list. */
 			list_move_tail(&page->list, &dirty);
+			left_dirty++;
 		}
 
 		cond_resched();
 	}
 
 	list_splice(&dirty, dirty_page_list);
+	return left_dirty;
 }
 
 static bool sgx_reclaimer_age(struct sgx_epc_page *epc_page)
@@ -388,17 +393,40 @@ void sgx_reclaim_direct(void)
 
 static int ksgxd(void *p)
 {
+	long ret;
+
 	set_freezable();
 
 	/*
 	 * Sanitize pages in order to recover from kexec(). The 2nd pass is
 	 * required for SECS pages, whose child pages blocked EREMOVE.
 	 */
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
+	ret = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (ret == -ECANCELED)
+		/* kthread stopped */
+		return 0;
 
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	ret = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	switch (ret) {
+	case 0:
+		/* success, no unsanitized pages */
+		break;
+
+	case -ECANCELED:
+		/* kthread stopped */
+		return 0;
+
+	default:
+		/*
+		 * Never expected to happen in a working driver. If it happens
+		 * the bug is expected to be in the sanitization process, but
+		 * successfully sanitized pages are still valid and driver can
+		 * be used and most importantly debugged without issues. To put
+		 * short, the global state of kernel is not corrupted so no
+		 * reason to do any more complicated rollback.
+		 */
+		pr_err("%ld unsanitized pages\n", ret);
+	}
 
 	while (!kthread_should_stop()) {
 		if (try_to_freeze())
Signature · 1 line
2.37.2
#3 lore raw

Re: [PATCH v2 2/6] x86/sgx: Do not consider unsanitized pages an error

Hi Jarkko,

Quoted 42 lines · Jarkko Sakkinen

In sgx_init(), if misc_register() fails or misc_register() succeeds but neither sgx_drv_init() nor sgx_vepc_init() succeeds, then ksgxd will be prematurely stopped. This may leave some unsanitized pages, which does not matter, because SGX will be disabled for the whole power cycle.

This triggers WARN_ON() because sgx_dirty_page_list ends up being non-empty, and dumps the call stack:

[    0.268103] sgx: EPC section 0x40200000-0x45f7ffff
[    0.268591] ------------[ cut here ]------------
[    0.268592] WARNING: CPU: 6 PID: 83 at
arch/x86/kernel/cpu/sgx/main.c:401 ksgxd+0x1b7/0x1d0
[    0.268598] Modules linked in:
[    0.268600] CPU: 6 PID: 83 Comm: ksgxd Not tainted 6.0.0-rc2 #382
[    0.268603] Hardware name: Dell Inc. XPS 13 9370/0RMYH9, BIOS 1.21.0
07/06/2022
[    0.268604] RIP: 0010:ksgxd+0x1b7/0x1d0
[    0.268607] Code: ff e9 f2 fe ff ff 48 89 df e8 75 07 0e 00 84 c0 0f
84 c3 fe ff ff 31 ff e8 e6 07 0e 00 84 c0 0f 85 94 fe ff ff e9 af fe ff
ff <0f> 0b e9 7f fe ff ff e8 dd 9c 95 00 66 66 2e 0f 1f 84 00 00 00 00
[    0.268608] RSP: 0000:ffffb6c7404f3ed8 EFLAGS: 00010287
[    0.268610] RAX: ffffb6c740431a10 RBX: ffff8dcd8117b400 RCX:
0000000000000000
[    0.268612] RDX: 0000000080000000 RSI: ffffb6c7404319d0 RDI:
00000000ffffffff
[    0.268613] RBP: ffff8dcd820a4d80 R08: ffff8dcd820a4180 R09:
ffff8dcd820a4180
[    0.268614] R10: 0000000000000000 R11: 0000000000000006 R12:
ffffb6c74006bce0
[    0.268615] R13: ffff8dcd80e63880 R14: ffffffffa8a60f10 R15:
0000000000000000
[    0.268616] FS:  0000000000000000(0000) GS:ffff8dcf25580000(0000)
knlGS:0000000000000000
[    0.268617] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.268619] CR2: 0000000000000000 CR3: 0000000213410001 CR4:
00000000003706e0
[    0.268620] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[    0.268621] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[    0.268622] Call Trace:
[    0.268624]  <TASK>
Quoted 9 lines
[    0.268627]  ? _raw_spin_lock_irqsave+0x24/0x60
[    0.268632]  ? _raw_spin_unlock_irqrestore+0x23/0x40
[    0.268634]  ? __kthread_parkme+0x36/0x90
[    0.268637]  kthread+0xe5/0x110
[    0.268639]  ? kthread_complete_and_exit+0x20/0x20
[    0.268642]  ret_from_fork+0x1f/0x30
[    0.268647]  </TASK>
[    0.268648] ---[ end trace 0000000000000000 ]---

Are you still planning to trim this?

Quoted 7 lines

Ultimately this can crash the kernel, if the following is set:

/proc/sys/kernel/panic_on_warn

In premature stop, print nothing, as the number is by practical means a random number. Otherwise, it is an indicator of a bug in the driver, and therefore print the number of unsanitized pages with pr_err().

I think that "print the number of unsanitized pages with pr_err()" contradicts the patch subject of "Do not consider unsanitized pages an error".

...

Quoted 35 lines
arch/x86/kernel/cpu/sgx/main.c +20 -4
@@ -388,17 +393,40 @@ void sgx_reclaim_direct(void)
 
 static int ksgxd(void *p)
 {
+	long ret;
+
 	set_freezable();
 
 	/*
 	 * Sanitize pages in order to recover from kexec(). The 2nd pass is
 	 * required for SECS pages, whose child pages blocked EREMOVE.
 	 */
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
+	ret = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (ret == -ECANCELED)
+		/* kthread stopped */
+		return 0;
 
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	ret = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	switch (ret) {
+	case 0:
+		/* success, no unsanitized pages */
+		break;
+
+	case -ECANCELED:
+		/* kthread stopped */
+		return 0;
+
+	default:
+		/*
+		 * Never expected to happen in a working driver. If it happens
+		 * the bug is expected to be in the sanitization process, but

arch/x86/kernel/cpu/sgx/main.c void sgx_reclaim_direct(void) · line 432

Quoted 10 lines
arch/x86/kernel/cpu/sgx/main.c +7 -0
+		 * successfully sanitized pages are still valid and driver can
+		 * be used and most importantly debugged without issues. To put
+		 * short, the global state of kernel is not corrupted so no
+		 * reason to do any more complicated rollback.
+		 */
+		pr_err("%ld unsanitized pages\n", ret);
+	}
 
 	while (!kthread_should_stop()) {
 		if (try_to_freeze())

I think I am missing something here. A lot of logic is added here but I do not see why it is necessary. ksgxd() knows via kthread_should_stop() if the reclaimer was canceled. I am thus wondering, could the above not be simplified to something similar to V1:

@@ -388,6 +393,8 @@ void sgx_reclaim_direct(void)

static int ksgxd(void *p)
{
+ unsigned long left_dirty;
+
set_freezable();

/*
@@ -395,10 +402,10 @@ static int ksgxd(void *p)
* required for SECS pages, whose child pages blocked EREMOVE. */
__sgx_sanitize_pages(&sgx_dirty_page_list);
- __sgx_sanitize_pages(&sgx_dirty_page_list);

- /* sanity check: */
- WARN_ON(!list_empty(&sgx_dirty_page_list));
+ left_dirty = __sgx_sanitize_pages(&sgx_dirty_page_list);
+ if (left_dirty && !kthread_should_stop())
+ pr_err("%lu unsanitized pages\n", left_dirty);

while (!kthread_should_stop()) {
if (try_to_freeze())

Reinette

#4 lore raw

Re: [PATCH v2 2/6] x86/sgx: Do not consider unsanitized pages an error

Quoted 74 lines · Reinette Chatre
Quoted 44 lines

  static int ksgxd(void *p)
  {

(quoted diff) +2 -0
+	long ret;
+

   set_freezable();

   /*
   * Sanitize pages in order to recover from kexec(). The 2nd pass is
   * required for SECS pages, whose child pages blocked EREMOVE. */

arch/x86/kernel/cpu/sgx/main.c +4 -2
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
+	ret = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (ret == -ECANCELED)
+		/* kthread stopped */
+		return 0;

arch/x86/kernel/cpu/sgx/main.c +13 -2
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	ret = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	switch (ret) {
+	case 0:
+		/* success, no unsanitized pages */
+		break;
+
+	case -ECANCELED:
+		/* kthread stopped */
+		return 0;
+
+	default:
+		/*
+		 * Never expected to happen in a working driver. If it

happens

(quoted diff) +1 -0
+		 * the bug is expected to be in the sanitization process,

but

(quoted diff) +1 -0
+		 * successfully sanitized pages are still valid and driver

can

(quoted diff) +1 -0
+		 * be used and most importantly debugged without issues. To

put

arch/x86/kernel/cpu/sgx/main.c +5 -0
+		 * short, the global state of kernel is not corrupted so no
+		 * reason to do any more complicated rollback.
+		 */
+		pr_err("%ld unsanitized pages\n", ret);
+	}
Quoted 3 lines


   while (!kthread_should_stop()) {
   if (try_to_freeze())

I think I am missing something here. A lot of logic is added here but I do not see why it is necessary.  ksgxd() knows via kthread_should_stop() if the reclaimer was canceled. I am thus wondering, could the above not be simplified to something similar to V1:

(quoted diff) +0 -0
@@ -388,6 +393,8 @@ void sgx_reclaim_direct(void)


 static int ksgxd(void *p)
 {

(quoted diff) +2 -0
+	unsigned long left_dirty;
+

  set_freezable();

  /*

arch/x86/kernel/cpu/sgx/main.c +0 -1
@@ -395,10 +402,10 @@ static int ksgxd(void *p)
  	 * required for SECS pages, whose child pages blocked EREMOVE.
  	 */
  	__sgx_sanitize_pages(&sgx_dirty_page_list);
-	__sgx_sanitize_pages(&sgx_dirty_page_list);

(quoted diff) +3 -2
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	left_dirty = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (left_dirty && !kthread_should_stop())
+		pr_err("%lu unsanitized pages\n", left_dirty);
Quoted 1 line

This basically means driver bug if I understand correctly. To be consistent with the behaviour of existing code, how about just WARN()?

	...
	left_dirty = __sgx_sanitize_pages(&sgx_dirty_page_list);
	WARN_ON(left_dirty && !kthread_should_stop());

It seems there's little value to print out the unsanitized pages here. The existing code doesn't print it anyway.

Signature · 2 lines
Thanks,
-Kai
author maintainer
#5 lore raw

Re: [PATCH v2 2/6] x86/sgx: Do not consider unsanitized pages an error

Quoted 80 lines · Kai
Quoted 74 lines · Reinette Chatre
Quoted 44 lines

  static int ksgxd(void *p)
  {

(quoted diff) +2 -0
+	long ret;
+

   set_freezable();

   /*
   * Sanitize pages in order to recover from kexec(). The 2nd pass is
   * required for SECS pages, whose child pages blocked EREMOVE. */

arch/x86/kernel/cpu/sgx/main.c +4 -2
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
+	ret = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (ret == -ECANCELED)
+		/* kthread stopped */
+		return 0;

arch/x86/kernel/cpu/sgx/main.c +13 -2
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	ret = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	switch (ret) {
+	case 0:
+		/* success, no unsanitized pages */
+		break;
+
+	case -ECANCELED:
+		/* kthread stopped */
+		return 0;
+
+	default:
+		/*
+		 * Never expected to happen in a working driver. If it

happens

(quoted diff) +1 -0
+		 * the bug is expected to be in the sanitization process,

but

(quoted diff) +1 -0
+		 * successfully sanitized pages are still valid and driver

can

(quoted diff) +1 -0
+		 * be used and most importantly debugged without issues. To

put

arch/x86/kernel/cpu/sgx/main.c +5 -0
+		 * short, the global state of kernel is not corrupted so no
+		 * reason to do any more complicated rollback.
+		 */
+		pr_err("%ld unsanitized pages\n", ret);
+	}
Quoted 3 lines


   while (!kthread_should_stop()) {
   if (try_to_freeze())

I think I am missing something here. A lot of logic is added here but I do not see why it is necessary.  ksgxd() knows via kthread_should_stop() if the reclaimer was canceled. I am thus wondering, could the above not be simplified to something similar to V1:

(quoted diff) +0 -0
@@ -388,6 +393,8 @@ void sgx_reclaim_direct(void)


 static int ksgxd(void *p)
 {

(quoted diff) +2 -0
+	unsigned long left_dirty;
+

  set_freezable();

  /*

arch/x86/kernel/cpu/sgx/main.c +0 -1
@@ -395,10 +402,10 @@ static int ksgxd(void *p)
  	 * required for SECS pages, whose child pages blocked EREMOVE.
  	 */
  	__sgx_sanitize_pages(&sgx_dirty_page_list);
-	__sgx_sanitize_pages(&sgx_dirty_page_list);

(quoted diff) +3 -2
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	left_dirty = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (left_dirty && !kthread_should_stop())
+		pr_err("%lu unsanitized pages\n", left_dirty);
Quoted 1 line

This basically means driver bug if I understand correctly. To be consistent with the behaviour of existing code, how about just WARN()?

Quoted 6 lines
	...
	left_dirty = __sgx_sanitize_pages(&sgx_dirty_page_list);
	WARN_ON(left_dirty && !kthread_should_stop());

It seems there's little value to print out the unsanitized pages here. The existing code doesn't print it anyway.

Using WARN IMHO here is too strong measure, given that it tear down the whole kernel, if panic_on_warn is enabled.

For debugging, any information is useful information, so would not make sense not print the number of pages, if that is available. That could very well point out the issue why all pages are not sanitized if there was a bug.

BR, Jarkko

author maintainer
#6 lore raw

Re: [PATCH v2 2/6] x86/sgx: Do not consider unsanitized pages an error

In reply to Reinette Chatre
Quoted 133 lines · Reinette Chatre

Hi Jarkko,

Quoted 42 lines · Jarkko Sakkinen

In sgx_init(), if misc_register() fails or misc_register() succeeds but neither sgx_drv_init() nor sgx_vepc_init() succeeds, then ksgxd will be prematurely stopped. This may leave some unsanitized pages, which does not matter, because SGX will be disabled for the whole power cycle.

This triggers WARN_ON() because sgx_dirty_page_list ends up being non-empty, and dumps the call stack:

[    0.268103] sgx: EPC section 0x40200000-0x45f7ffff
[    0.268591] ------------[ cut here ]------------
[    0.268592] WARNING: CPU: 6 PID: 83 at
arch/x86/kernel/cpu/sgx/main.c:401 ksgxd+0x1b7/0x1d0
[    0.268598] Modules linked in:
[    0.268600] CPU: 6 PID: 83 Comm: ksgxd Not tainted 6.0.0-rc2 #382
[    0.268603] Hardware name: Dell Inc. XPS 13 9370/0RMYH9, BIOS 1.21.0
07/06/2022
[    0.268604] RIP: 0010:ksgxd+0x1b7/0x1d0
[    0.268607] Code: ff e9 f2 fe ff ff 48 89 df e8 75 07 0e 00 84 c0 0f
84 c3 fe ff ff 31 ff e8 e6 07 0e 00 84 c0 0f 85 94 fe ff ff e9 af fe ff
ff <0f> 0b e9 7f fe ff ff e8 dd 9c 95 00 66 66 2e 0f 1f 84 00 00 00 00
[    0.268608] RSP: 0000:ffffb6c7404f3ed8 EFLAGS: 00010287
[    0.268610] RAX: ffffb6c740431a10 RBX: ffff8dcd8117b400 RCX:
0000000000000000
[    0.268612] RDX: 0000000080000000 RSI: ffffb6c7404319d0 RDI:
00000000ffffffff
[    0.268613] RBP: ffff8dcd820a4d80 R08: ffff8dcd820a4180 R09:
ffff8dcd820a4180
[    0.268614] R10: 0000000000000000 R11: 0000000000000006 R12:
ffffb6c74006bce0
[    0.268615] R13: ffff8dcd80e63880 R14: ffffffffa8a60f10 R15:
0000000000000000
[    0.268616] FS:  0000000000000000(0000) GS:ffff8dcf25580000(0000)
knlGS:0000000000000000
[    0.268617] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.268619] CR2: 0000000000000000 CR3: 0000000213410001 CR4:
00000000003706e0
[    0.268620] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[    0.268621] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[    0.268622] Call Trace:
[    0.268624]  <TASK>
Quoted 9 lines
[    0.268627]  ? _raw_spin_lock_irqsave+0x24/0x60
[    0.268632]  ? _raw_spin_unlock_irqrestore+0x23/0x40
[    0.268634]  ? __kthread_parkme+0x36/0x90
[    0.268637]  kthread+0xe5/0x110
[    0.268639]  ? kthread_complete_and_exit+0x20/0x20
[    0.268642]  ret_from_fork+0x1f/0x30
[    0.268647]  </TASK>
[    0.268648] ---[ end trace 0000000000000000 ]---

Are you still planning to trim this?

Quoted 7 lines

Ultimately this can crash the kernel, if the following is set:

/proc/sys/kernel/panic_on_warn

In premature stop, print nothing, as the number is by practical means a random number. Otherwise, it is an indicator of a bug in the driver, and therefore print the number of unsanitized pages with pr_err().

I think that "print the number of unsanitized pages with pr_err()" contradicts the patch subject of "Do not consider unsanitized pages an error".

...

Quoted 35 lines
arch/x86/kernel/cpu/sgx/main.c +20 -4
@@ -388,17 +393,40 @@ void sgx_reclaim_direct(void)
 
 static int ksgxd(void *p)
 {
+	long ret;
+
 	set_freezable();
 
 	/*
 	 * Sanitize pages in order to recover from kexec(). The 2nd pass is
 	 * required for SECS pages, whose child pages blocked EREMOVE.
 	 */
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
+	ret = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (ret == -ECANCELED)
+		/* kthread stopped */
+		return 0;
 
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	ret = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	switch (ret) {
+	case 0:
+		/* success, no unsanitized pages */
+		break;
+
+	case -ECANCELED:
+		/* kthread stopped */
+		return 0;
+
+	default:
+		/*
+		 * Never expected to happen in a working driver. If it happens
+		 * the bug is expected to be in the sanitization process, but

arch/x86/kernel/cpu/sgx/main.c void sgx_reclaim_direct(void) · line 432

Quoted 10 lines
arch/x86/kernel/cpu/sgx/main.c +7 -0
+		 * successfully sanitized pages are still valid and driver can
+		 * be used and most importantly debugged without issues. To put
+		 * short, the global state of kernel is not corrupted so no
+		 * reason to do any more complicated rollback.
+		 */
+		pr_err("%ld unsanitized pages\n", ret);
+	}
 
 	while (!kthread_should_stop()) {
 		if (try_to_freeze())

I think I am missing something here. A lot of logic is added here but I do not see why it is necessary. ksgxd() knows via kthread_should_stop() if the reclaimer was canceled. I am thus wondering, could the above not be simplified to something similar to V1:

arch/x86/kernel/cpu/sgx/main.c +2 -0
@@ -388,6 +393,8 @@ void sgx_reclaim_direct(void)
 
 static int ksgxd(void *p)
 {
+	unsigned long left_dirty;
+
 	set_freezable();
 
 	/*

arch/x86/kernel/cpu/sgx/main.c static int ksgxd(void *p) · line 404

Quoted 3 lines
arch/x86/kernel/cpu/sgx/main.c +0 -0
@@ -395,10 +402,10 @@ static int ksgxd(void *p)
 	 * required for SECS pages, whose child pages blocked EREMOVE.
 	 */
 	__sgx_sanitize_pages(&sgx_dirty_page_list);

IMHO, would make sense also to have here:

        if (!kthread_should_stop())
                return 0;

arch/x86/kernel/cpu/sgx/main.c void sgx_reclaim_direct(void)

Quoted 7 lines
arch/x86/kernel/cpu/sgx/main.c +3 -3
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
 
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	left_dirty = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (left_dirty && !kthread_should_stop())
+		pr_err("%lu unsanitized pages\n", left_dirty);

That would be incorrect, if the function returned because of kthread stopped.

If you do the check here you already have a window where kthread could have been stopped anyhow.

So even this would be less correct:

        if (kthreas_should_stop()) {
                return 0;
        }  else if (left_dirty) {
                pr_err("%lu unsanitized pages\n", left_dirty);
        }

So in the end you end as complicated and less correct fix. This all is explained in the commit message.

If you unconditionally print error, you don't have a meaning for the number of unsanitized pags.

BR, Jarkko

author maintainer
#7 lore raw

Re: [PATCH v2 2/6] x86/sgx: Do not consider unsanitized pages an error

Quoted 165 lines · Jarkko Sakkinen
Quoted 133 lines · Reinette Chatre

Hi Jarkko,

Quoted 42 lines · Jarkko Sakkinen

In sgx_init(), if misc_register() fails or misc_register() succeeds but neither sgx_drv_init() nor sgx_vepc_init() succeeds, then ksgxd will be prematurely stopped. This may leave some unsanitized pages, which does not matter, because SGX will be disabled for the whole power cycle.

This triggers WARN_ON() because sgx_dirty_page_list ends up being non-empty, and dumps the call stack:

[    0.268103] sgx: EPC section 0x40200000-0x45f7ffff
[    0.268591] ------------[ cut here ]------------
[    0.268592] WARNING: CPU: 6 PID: 83 at
arch/x86/kernel/cpu/sgx/main.c:401 ksgxd+0x1b7/0x1d0
[    0.268598] Modules linked in:
[    0.268600] CPU: 6 PID: 83 Comm: ksgxd Not tainted 6.0.0-rc2 #382
[    0.268603] Hardware name: Dell Inc. XPS 13 9370/0RMYH9, BIOS 1.21.0
07/06/2022
[    0.268604] RIP: 0010:ksgxd+0x1b7/0x1d0
[    0.268607] Code: ff e9 f2 fe ff ff 48 89 df e8 75 07 0e 00 84 c0 0f
84 c3 fe ff ff 31 ff e8 e6 07 0e 00 84 c0 0f 85 94 fe ff ff e9 af fe ff
ff <0f> 0b e9 7f fe ff ff e8 dd 9c 95 00 66 66 2e 0f 1f 84 00 00 00 00
[    0.268608] RSP: 0000:ffffb6c7404f3ed8 EFLAGS: 00010287
[    0.268610] RAX: ffffb6c740431a10 RBX: ffff8dcd8117b400 RCX:
0000000000000000
[    0.268612] RDX: 0000000080000000 RSI: ffffb6c7404319d0 RDI:
00000000ffffffff
[    0.268613] RBP: ffff8dcd820a4d80 R08: ffff8dcd820a4180 R09:
ffff8dcd820a4180
[    0.268614] R10: 0000000000000000 R11: 0000000000000006 R12:
ffffb6c74006bce0
[    0.268615] R13: ffff8dcd80e63880 R14: ffffffffa8a60f10 R15:
0000000000000000
[    0.268616] FS:  0000000000000000(0000) GS:ffff8dcf25580000(0000)
knlGS:0000000000000000
[    0.268617] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.268619] CR2: 0000000000000000 CR3: 0000000213410001 CR4:
00000000003706e0
[    0.268620] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[    0.268621] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[    0.268622] Call Trace:
[    0.268624]  <TASK>
Quoted 9 lines
[    0.268627]  ? _raw_spin_lock_irqsave+0x24/0x60
[    0.268632]  ? _raw_spin_unlock_irqrestore+0x23/0x40
[    0.268634]  ? __kthread_parkme+0x36/0x90
[    0.268637]  kthread+0xe5/0x110
[    0.268639]  ? kthread_complete_and_exit+0x20/0x20
[    0.268642]  ret_from_fork+0x1f/0x30
[    0.268647]  </TASK>
[    0.268648] ---[ end trace 0000000000000000 ]---

Are you still planning to trim this?

Quoted 7 lines

Ultimately this can crash the kernel, if the following is set:

/proc/sys/kernel/panic_on_warn

In premature stop, print nothing, as the number is by practical means a random number. Otherwise, it is an indicator of a bug in the driver, and therefore print the number of unsanitized pages with pr_err().

I think that "print the number of unsanitized pages with pr_err()" contradicts the patch subject of "Do not consider unsanitized pages an error".

...

Quoted 35 lines
arch/x86/kernel/cpu/sgx/main.c +20 -4
@@ -388,17 +393,40 @@ void sgx_reclaim_direct(void)
 
 static int ksgxd(void *p)
 {
+	long ret;
+
 	set_freezable();
 
 	/*
 	 * Sanitize pages in order to recover from kexec(). The 2nd pass is
 	 * required for SECS pages, whose child pages blocked EREMOVE.
 	 */
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
+	ret = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (ret == -ECANCELED)
+		/* kthread stopped */
+		return 0;
 
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	ret = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	switch (ret) {
+	case 0:
+		/* success, no unsanitized pages */
+		break;
+
+	case -ECANCELED:
+		/* kthread stopped */
+		return 0;
+
+	default:
+		/*
+		 * Never expected to happen in a working driver. If it happens
+		 * the bug is expected to be in the sanitization process, but

arch/x86/kernel/cpu/sgx/main.c void sgx_reclaim_direct(void) · line 432

Quoted 10 lines
arch/x86/kernel/cpu/sgx/main.c +7 -0
+		 * successfully sanitized pages are still valid and driver can
+		 * be used and most importantly debugged without issues. To put
+		 * short, the global state of kernel is not corrupted so no
+		 * reason to do any more complicated rollback.
+		 */
+		pr_err("%ld unsanitized pages\n", ret);
+	}
 
 	while (!kthread_should_stop()) {
 		if (try_to_freeze())

I think I am missing something here. A lot of logic is added here but I do not see why it is necessary. ksgxd() knows via kthread_should_stop() if the reclaimer was canceled. I am thus wondering, could the above not be simplified to something similar to V1:

arch/x86/kernel/cpu/sgx/main.c +2 -0
@@ -388,6 +393,8 @@ void sgx_reclaim_direct(void)
 
 static int ksgxd(void *p)
 {
+	unsigned long left_dirty;
+
 	set_freezable();
 
 	/*

arch/x86/kernel/cpu/sgx/main.c static int ksgxd(void *p) · line 404

Quoted 3 lines
arch/x86/kernel/cpu/sgx/main.c +0 -0
@@ -395,10 +402,10 @@ static int ksgxd(void *p)
 	 * required for SECS pages, whose child pages blocked EREMOVE.
 	 */
 	__sgx_sanitize_pages(&sgx_dirty_page_list);

IMHO, would make sense also to have here:

        if (!kthread_should_stop())
                return 0;

arch/x86/kernel/cpu/sgx/main.c void sgx_reclaim_direct(void)

Quoted 7 lines
arch/x86/kernel/cpu/sgx/main.c +3 -3
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
 
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	left_dirty = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (left_dirty && !kthread_should_stop())
+		pr_err("%lu unsanitized pages\n", left_dirty);

That would be incorrect, if the function returned because of kthread stopped.

If you do the check here you already have a window where kthread could have been stopped anyhow.

So even this would be less correct:

        if (kthreas_should_stop()) {
                return 0;
        }  else if (left_dirty) {
                pr_err("%lu unsanitized pages\n", left_dirty);
        }
Quoted 5 lines

So in the end you end as complicated and less correct fix. This all is explained in the commit message.

If you unconditionally print error, you don't have a meaning for the number of unsanitized pags.

If you add my long comment explaining the error case, the SLOC size is almost the same. That takes most space in my patch.

BR, Jarkko

author maintainer
#8 lore raw

Re: [PATCH v2 2/6] x86/sgx: Do not consider unsanitized pages an error

Quoted 166 lines · Jarkko Sakkinen
Quoted 165 lines · Jarkko Sakkinen
Quoted 133 lines · Reinette Chatre

Hi Jarkko,

Quoted 42 lines · Jarkko Sakkinen

In sgx_init(), if misc_register() fails or misc_register() succeeds but neither sgx_drv_init() nor sgx_vepc_init() succeeds, then ksgxd will be prematurely stopped. This may leave some unsanitized pages, which does not matter, because SGX will be disabled for the whole power cycle.

This triggers WARN_ON() because sgx_dirty_page_list ends up being non-empty, and dumps the call stack:

[    0.268103] sgx: EPC section 0x40200000-0x45f7ffff
[    0.268591] ------------[ cut here ]------------
[    0.268592] WARNING: CPU: 6 PID: 83 at
arch/x86/kernel/cpu/sgx/main.c:401 ksgxd+0x1b7/0x1d0
[    0.268598] Modules linked in:
[    0.268600] CPU: 6 PID: 83 Comm: ksgxd Not tainted 6.0.0-rc2 #382
[    0.268603] Hardware name: Dell Inc. XPS 13 9370/0RMYH9, BIOS 1.21.0
07/06/2022
[    0.268604] RIP: 0010:ksgxd+0x1b7/0x1d0
[    0.268607] Code: ff e9 f2 fe ff ff 48 89 df e8 75 07 0e 00 84 c0 0f
84 c3 fe ff ff 31 ff e8 e6 07 0e 00 84 c0 0f 85 94 fe ff ff e9 af fe ff
ff <0f> 0b e9 7f fe ff ff e8 dd 9c 95 00 66 66 2e 0f 1f 84 00 00 00 00
[    0.268608] RSP: 0000:ffffb6c7404f3ed8 EFLAGS: 00010287
[    0.268610] RAX: ffffb6c740431a10 RBX: ffff8dcd8117b400 RCX:
0000000000000000
[    0.268612] RDX: 0000000080000000 RSI: ffffb6c7404319d0 RDI:
00000000ffffffff
[    0.268613] RBP: ffff8dcd820a4d80 R08: ffff8dcd820a4180 R09:
ffff8dcd820a4180
[    0.268614] R10: 0000000000000000 R11: 0000000000000006 R12:
ffffb6c74006bce0
[    0.268615] R13: ffff8dcd80e63880 R14: ffffffffa8a60f10 R15:
0000000000000000
[    0.268616] FS:  0000000000000000(0000) GS:ffff8dcf25580000(0000)
knlGS:0000000000000000
[    0.268617] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.268619] CR2: 0000000000000000 CR3: 0000000213410001 CR4:
00000000003706e0
[    0.268620] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[    0.268621] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[    0.268622] Call Trace:
[    0.268624]  <TASK>
Quoted 9 lines
[    0.268627]  ? _raw_spin_lock_irqsave+0x24/0x60
[    0.268632]  ? _raw_spin_unlock_irqrestore+0x23/0x40
[    0.268634]  ? __kthread_parkme+0x36/0x90
[    0.268637]  kthread+0xe5/0x110
[    0.268639]  ? kthread_complete_and_exit+0x20/0x20
[    0.268642]  ret_from_fork+0x1f/0x30
[    0.268647]  </TASK>
[    0.268648] ---[ end trace 0000000000000000 ]---

Are you still planning to trim this?

Quoted 7 lines

Ultimately this can crash the kernel, if the following is set:

/proc/sys/kernel/panic_on_warn

In premature stop, print nothing, as the number is by practical means a random number. Otherwise, it is an indicator of a bug in the driver, and therefore print the number of unsanitized pages with pr_err().

I think that "print the number of unsanitized pages with pr_err()" contradicts the patch subject of "Do not consider unsanitized pages an error".

...

Quoted 35 lines
arch/x86/kernel/cpu/sgx/main.c +20 -4
@@ -388,17 +393,40 @@ void sgx_reclaim_direct(void)
 
 static int ksgxd(void *p)
 {
+	long ret;
+
 	set_freezable();
 
 	/*
 	 * Sanitize pages in order to recover from kexec(). The 2nd pass is
 	 * required for SECS pages, whose child pages blocked EREMOVE.
 	 */
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
+	ret = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (ret == -ECANCELED)
+		/* kthread stopped */
+		return 0;
 
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	ret = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	switch (ret) {
+	case 0:
+		/* success, no unsanitized pages */
+		break;
+
+	case -ECANCELED:
+		/* kthread stopped */
+		return 0;
+
+	default:
+		/*
+		 * Never expected to happen in a working driver. If it happens
+		 * the bug is expected to be in the sanitization process, but

arch/x86/kernel/cpu/sgx/main.c void sgx_reclaim_direct(void) · line 432

Quoted 10 lines
arch/x86/kernel/cpu/sgx/main.c +7 -0
+		 * successfully sanitized pages are still valid and driver can
+		 * be used and most importantly debugged without issues. To put
+		 * short, the global state of kernel is not corrupted so no
+		 * reason to do any more complicated rollback.
+		 */
+		pr_err("%ld unsanitized pages\n", ret);
+	}
 
 	while (!kthread_should_stop()) {
 		if (try_to_freeze())

I think I am missing something here. A lot of logic is added here but I do not see why it is necessary. ksgxd() knows via kthread_should_stop() if the reclaimer was canceled. I am thus wondering, could the above not be simplified to something similar to V1:

arch/x86/kernel/cpu/sgx/main.c +2 -0
@@ -388,6 +393,8 @@ void sgx_reclaim_direct(void)
 
 static int ksgxd(void *p)
 {
+	unsigned long left_dirty;
+
 	set_freezable();
 
 	/*

arch/x86/kernel/cpu/sgx/main.c static int ksgxd(void *p) · line 404

Quoted 3 lines
arch/x86/kernel/cpu/sgx/main.c +0 -0
@@ -395,10 +402,10 @@ static int ksgxd(void *p)
 	 * required for SECS pages, whose child pages blocked EREMOVE.
 	 */
 	__sgx_sanitize_pages(&sgx_dirty_page_list);

IMHO, would make sense also to have here:

        if (!kthread_should_stop())
                return 0;

arch/x86/kernel/cpu/sgx/main.c void sgx_reclaim_direct(void)

Quoted 7 lines
arch/x86/kernel/cpu/sgx/main.c +3 -3
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
 
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	left_dirty = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (left_dirty && !kthread_should_stop())
+		pr_err("%lu unsanitized pages\n", left_dirty);

That would be incorrect, if the function returned because of kthread stopped.

If you do the check here you already have a window where kthread could have been stopped anyhow.

So even this would be less correct:

        if (kthreas_should_stop()) {
                return 0;
        }  else if (left_dirty) {
                pr_err("%lu unsanitized pages\n", left_dirty);
        }
Quoted 8 lines
Quoted 5 lines

So in the end you end as complicated and less correct fix. This all is explained in the commit message.

If you unconditionally print error, you don't have a meaning for the number of unsanitized pags.

If you add my long comment explaining the error case, the SLOC size is almost the same. That takes most space in my patch.

Printing pages if the thread was stopped is just making the bug look different and have less output, it does not fix anything, except prevent kernel panic.

BR, Jarkko

#9 lore raw

Re: [PATCH v2 2/6] x86/sgx: Do not consider unsanitized pages an error

In reply to Jarkko Sakkinen

Hi Jarkko,

Quoted 24 lines · Jarkko Sakkinen
Quoted 17 lines · Reinette Chatre

On 8/31/2022 10:38 AM, Jarkko Sakkinen wrote:

I think I am missing something here. A lot of logic is added here but I do not see why it is necessary. ksgxd() knows via kthread_should_stop() if the reclaimer was canceled. I am thus wondering, could the above not be simplified to something similar to V1:

arch/x86/kernel/cpu/sgx/main.c +2 -0
@@ -388,6 +393,8 @@ void sgx_reclaim_direct(void)
 
 static int ksgxd(void *p)
 {
+	unsigned long left_dirty;
+
 	set_freezable();
 
 	/*

arch/x86/kernel/cpu/sgx/main.c static int ksgxd(void *p) · line 404

Quoted 3 lines
arch/x86/kernel/cpu/sgx/main.c +0 -0
@@ -395,10 +402,10 @@ static int ksgxd(void *p)
 	 * required for SECS pages, whose child pages blocked EREMOVE.
 	 */
 	__sgx_sanitize_pages(&sgx_dirty_page_list);

IMHO, would make sense also to have here:

Quoted 3 lines
        if (!kthread_should_stop())
                return 0;

Would this not prematurely stop the thread when it should not be?

Quoted 10 lines

arch/x86/kernel/cpu/sgx/main.c void sgx_reclaim_direct(void)

Quoted 7 lines
arch/x86/kernel/cpu/sgx/main.c +3 -3
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
 
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	left_dirty = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (left_dirty && !kthread_should_stop())
+		pr_err("%lu unsanitized pages\n", left_dirty);

That would be incorrect, if the function returned because of kthread stopped.

I should have highlighted this but in my example I changed left_dirty to be "unsigned long" with the intention that the "return -ECANCELED" is replaced with "return 0".

__sgx_sanitize_pages() returns 0 when it exits because of kthread stopped.

To elaborate I was thinking about:

+static unsigned long __sgx_sanitize_pages(struct list_head *dirty_page_list)
{
+ unsigned long left_dirty = 0;
struct sgx_epc_page *page;
LIST_HEAD(dirty);
int ret;

- /* dirty_page_list is thread-local, no need for a lock: */
while (!list_empty(dirty_page_list)) {
if (kthread_should_stop())
- return;
+ return 0;

page = list_first_entry(dirty_page_list, struct sgx_epc_page, list);

@@ -92,12 +95,14 @@ static void __sgx_sanitize_pages(struct list_head *dirty_page_list)
} else {
/* The page is not yet clean - move to the dirty list. */ list_move_tail(&page->list, &dirty);
+ left_dirty++;
}

cond_resched();
}

list_splice(&dirty, dirty_page_list);
+ return left_dirty;
}

and then with what I had in previous email the checks should work:

@@ -388,6 +393,8 @@ void sgx_reclaim_direct(void)

static int ksgxd(void *p)
{
+ unsigned long left_dirty;
+
set_freezable();

/*
@@ -395,10 +402,10 @@ static int ksgxd(void *p)
* required for SECS pages, whose child pages blocked EREMOVE. */
__sgx_sanitize_pages(&sgx_dirty_page_list);
- __sgx_sanitize_pages(&sgx_dirty_page_list);

- /* sanity check: */
- WARN_ON(!list_empty(&sgx_dirty_page_list));
+ left_dirty = __sgx_sanitize_pages(&sgx_dirty_page_list);
+ if (left_dirty && !kthread_should_stop())
+ pr_err("%lu unsanitized pages\n", left_dirty);

while (!kthread_should_stop()) {
if (try_to_freeze())

Quoted 12 lines

If you do the check here you already have a window where kthread could have been stopped anyhow.

So even this would be less correct:

        if (kthreas_should_stop()) {
                return 0;
        }  else if (left_dirty) {
                pr_err("%lu unsanitized pages\n", left_dirty);
        }
Quoted 5 lines

So in the end you end as complicated and less correct fix. This all is explained in the commit message.

If you unconditionally print error, you don't have a meaning for the number of unsanitized pags.

Understood that the goal is to only print the number of unsanitized pages if ksgxd has not been stopped prematurely.

Reinette

author maintainer
#10 lore raw

Re: [PATCH v2 2/6] x86/sgx: Do not consider unsanitized pages an error

Quoted 45 lines · Reinette Chatre

Hi Jarkko,

Quoted 24 lines · Jarkko Sakkinen
Quoted 17 lines · Reinette Chatre

On 8/31/2022 10:38 AM, Jarkko Sakkinen wrote:

I think I am missing something here. A lot of logic is added here but I do not see why it is necessary. ksgxd() knows via kthread_should_stop() if the reclaimer was canceled. I am thus wondering, could the above not be simplified to something similar to V1:

arch/x86/kernel/cpu/sgx/main.c +2 -0
@@ -388,6 +393,8 @@ void sgx_reclaim_direct(void)
 
 static int ksgxd(void *p)
 {
+	unsigned long left_dirty;
+
 	set_freezable();
 
 	/*

arch/x86/kernel/cpu/sgx/main.c static int ksgxd(void *p) · line 404

Quoted 3 lines
arch/x86/kernel/cpu/sgx/main.c +0 -0
@@ -395,10 +402,10 @@ static int ksgxd(void *p)
 	 * required for SECS pages, whose child pages blocked EREMOVE.
 	 */
 	__sgx_sanitize_pages(&sgx_dirty_page_list);

IMHO, would make sense also to have here:

Quoted 3 lines
        if (!kthread_should_stop())
                return 0;

Would this not prematurely stop the thread when it should not be?

Quoted 10 lines

arch/x86/kernel/cpu/sgx/main.c void sgx_reclaim_direct(void)

Quoted 7 lines
arch/x86/kernel/cpu/sgx/main.c +3 -3
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
 
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	left_dirty = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (left_dirty && !kthread_should_stop())
+		pr_err("%lu unsanitized pages\n", left_dirty);

That would be incorrect, if the function returned because of kthread stopped.

Quoted 3 lines

I should have highlighted this but in my example I changed left_dirty to be "unsigned long" with the intention that the "return -ECANCELED" is replaced with "return 0".

It wasn't supposed to be, it's an error. Thanks for spotting that.

Quoted 78 lines

__sgx_sanitize_pages() returns 0 when it exits because of kthread stopped.

To elaborate I was thinking about:

arch/x86/kernel/cpu/sgx/main.c +5 -2
+static unsigned long __sgx_sanitize_pages(struct list_head *dirty_page_list)
 {
+	unsigned long left_dirty = 0;
 	struct sgx_epc_page *page;
 	LIST_HEAD(dirty);
 	int ret;
 
-	/* dirty_page_list is thread-local, no need for a lock: */
 	while (!list_empty(dirty_page_list)) {
 		if (kthread_should_stop())
-			return;
+			return 0;
 
 		page = list_first_entry(dirty_page_list, struct sgx_epc_page, list);
@@ -92,12 +95,14 @@ static void __sgx_sanitize_pages(struct list_head *dirty_page_list)
 		} else {
 			/* The page is not yet clean - move to the dirty list. */
 			list_move_tail(&page->list, &dirty);
+			left_dirty++;
 		}
 
 		cond_resched();
 	}
 
 	list_splice(&dirty, dirty_page_list);
+	return left_dirty;
 }
 
 

and then with what I had in previous email the checks should work:

arch/x86/kernel/cpu/sgx/main.c +5 -3
@@ -388,6 +393,8 @@ void sgx_reclaim_direct(void)
 
 static int ksgxd(void *p)
 {
+	unsigned long left_dirty;
+
 	set_freezable();
 
 	/*
@@ -395,10 +402,10 @@ static int ksgxd(void *p)
 	 * required for SECS pages, whose child pages blocked EREMOVE.
 	 */
 	__sgx_sanitize_pages(&sgx_dirty_page_list);
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
 
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	left_dirty = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	if (left_dirty && !kthread_should_stop())
+		pr_err("%lu unsanitized pages\n", left_dirty);
 
 	while (!kthread_should_stop()) {
 		if (try_to_freeze())
Quoted 17 lines

If you do the check here you already have a window where kthread could have been stopped anyhow.

So even this would be less correct:

        if (kthreas_should_stop()) {
                return 0;
        }  else if (left_dirty) {
                pr_err("%lu unsanitized pages\n", left_dirty);
        }

So in the end you end as complicated and less correct fix. This all is explained in the commit message.

Quoted 6 lines
Quoted 2 lines

If you unconditionally print error, you don't have a meaning for the number of unsanitized pags.

Understood that the goal is to only print the number of unsanitized pages if ksgxd has not been stopped prematurely.

Yeah, and thus give as useful information for sysadmin/developer as we can.

BR, Jarkko

author maintainer
#11 lore raw

Re: [PATCH v2 2/6] x86/sgx: Do not consider unsanitized pages an error

Quoted 6 lines · Jarkko Sakkinen
Quoted 3 lines

Understood that the goal is to only print the
number of unsanitized pages if ksgxd has not been
stopped prematurely.

Yeah, and thus give as useful information for sysadmin/developer as we can.

I figured out how to get best of both worlds. See the attached patch. I'll send formal series later on.

Keeps the accurancy, just postpones the exit.

BR, Jarkko

From 31c43c3276667cef0a7f0687d489552f26da877b Mon Sep 17 00:00:00 2001
From: Jarkko Sakkinen <[email protected]>
Date: Thu, 25 Aug 2022 08:12:30 +0300
Subject: [PATCH] x86/sgx: Do not consider unsanitized pages an error

In sgx_init(), if misc_register() fails or misc_register() succeeds but neither sgx_drv_init() nor sgx_vepc_init() succeeds, then ksgxd will be prematurely stopped. This may leave some unsanitized pages, which does not matter, because SGX will be disabled for the whole power cycle.

This triggers WARN_ON() because sgx_dirty_page_list ends up being non-empty, and dumps the call stack:

[    0.268103] sgx: EPC section 0x40200000-0x45f7ffff
[    0.268591] ------------[ cut here ]------------
[    0.268592] WARNING: CPU: 6 PID: 83 at
arch/x86/kernel/cpu/sgx/main.c:401 ksgxd+0x1b7/0x1d0
[    0.268598] Modules linked in:
[    0.268600] CPU: 6 PID: 83 Comm: ksgxd Not tainted 6.0.0-rc2 #382
[    0.268603] Hardware name: Dell Inc. XPS 13 9370/0RMYH9, BIOS 1.21.0
07/06/2022
[    0.268604] RIP: 0010:ksgxd+0x1b7/0x1d0
[    0.268607] Code: ff e9 f2 fe ff ff 48 89 df e8 75 07 0e 00 84 c0 0f
84 c3 fe ff ff 31 ff e8 e6 07 0e 00 84 c0 0f 85 94 fe ff ff e9 af fe ff
ff <0f> 0b e9 7f fe ff ff e8 dd 9c 95 00 66 66 2e 0f 1f 84 00 00 00 00
[    0.268608] RSP: 0000:ffffb6c7404f3ed8 EFLAGS: 00010287
[    0.268610] RAX: ffffb6c740431a10 RBX: ffff8dcd8117b400 RCX:
0000000000000000
[    0.268612] RDX: 0000000080000000 RSI: ffffb6c7404319d0 RDI:
00000000ffffffff
[    0.268613] RBP: ffff8dcd820a4d80 R08: ffff8dcd820a4180 R09:
ffff8dcd820a4180
[    0.268614] R10: 0000000000000000 R11: 0000000000000006 R12:
ffffb6c74006bce0
[    0.268615] R13: ffff8dcd80e63880 R14: ffffffffa8a60f10 R15:
0000000000000000
[    0.268616] FS:  0000000000000000(0000) GS:ffff8dcf25580000(0000)
knlGS:0000000000000000
[    0.268617] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.268619] CR2: 0000000000000000 CR3: 0000000213410001 CR4:
00000000003706e0
[    0.268620] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[    0.268621] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[    0.268622] Call Trace:
[    0.268624]  <TASK>
[    0.268627]  ? _raw_spin_lock_irqsave+0x24/0x60
[    0.268632]  ? _raw_spin_unlock_irqrestore+0x23/0x40
[    0.268634]  ? __kthread_parkme+0x36/0x90
[    0.268637]  kthread+0xe5/0x110
[    0.268639]  ? kthread_complete_and_exit+0x20/0x20
[    0.268642]  ret_from_fork+0x1f/0x30
[    0.268647]  </TASK>
[    0.268648] ---[ end trace 0000000000000000 ]---

Ultimately this can crash the kernel, if the following is set:

/proc/sys/kernel/panic_on_warn

In premature stop, print nothing, as the number is by practical means a random number. Otherwise, it is an indicator of a bug in the driver, and therefore print the number of unsanitized pages with pr_err().

Fixes 51ab30eb2ad4 ("x86/sgx: Replace section->init_laundry_list with sgx_dirty_page_list")
Cc [email protected] # v5.13+

v6:
- Address Reinette's feedback:
https://lore.kernel.org/linux-sgx/Yw6%2FiTzSdSw%2FY%[email protected]/

v5:
- Add the klog dump and sysctl option to the commit message.

v4:
- Explain expectations for dirty_page_list in the function header, instead of an inline comment.
- Improve commit message to explain the conditions better.
- Return the number of pages left dirty to ksgxd() and print warning after the 2nd call, if there are any.

v3:
- Remove WARN_ON().
- Tuned comments and the commit message a bit.

v2:
- Replaced WARN_ON() with optional pr_info() inside __sgx_sanitize_pages().
- Rewrote the commit message.
- Added the fixes tag.

---
 arch/x86/kernel/cpu/sgx/main.c | 33 ++++++++++++++++++++++++++-------
 1 file changed, 26 insertions(+), 7 deletions(-)
arch/x86/kernel/cpu/sgx/main.c +26 -7
index 515e2a5f25bb..f29dcaddd140 100644
@@ -49,17 +49,23 @@ static LIST_HEAD(sgx_dirty_page_list);
  * Reset post-kexec EPC pages to the uninitialized state. The pages are removed
  * from the input list, and made available for the page allocator. SECS pages
  * prepending their children in the input list are left intact.
+ *
+ * Contents of the @dirty_page_list must be thread-local, i.e.
+ * not shared by multiple threads.
+ *
+ * Return 0 when sanitization was successful or kthread was stopped, and the
+ * number of unsanitized pages otherwise.
  */
-static void __sgx_sanitize_pages(struct list_head *dirty_page_list)
+static unsigned long __sgx_sanitize_pages(struct list_head *dirty_page_list)
 {
 	struct sgx_epc_page *page;
+	long left_dirty = 0;
 	LIST_HEAD(dirty);
 	int ret;
 
-	/* dirty_page_list is thread-local, no need for a lock: */
 	while (!list_empty(dirty_page_list)) {
 		if (kthread_should_stop())
-			return;
+			return 0;
 
 		page = list_first_entry(dirty_page_list, struct sgx_epc_page, list);
 
@@ -92,12 +98,14 @@ static void __sgx_sanitize_pages(struct list_head *dirty_page_list)
 		} else {
 			/* The page is not yet clean - move to the dirty list. */
 			list_move_tail(&page->list, &dirty);
+			left_dirty++;
 		}
 
 		cond_resched();
 	}
 
 	list_splice(&dirty, dirty_page_list);
+	return left_dirty;
 }
 
 static bool sgx_reclaimer_age(struct sgx_epc_page *epc_page)
@@ -388,17 +396,28 @@ void sgx_reclaim_direct(void)
 
 static int ksgxd(void *p)
 {
+	unsigned long left_dirty;
+
 	set_freezable();
 
 	/*
 	 * Sanitize pages in order to recover from kexec(). The 2nd pass is
 	 * required for SECS pages, whose child pages blocked EREMOVE.
 	 */
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
-	__sgx_sanitize_pages(&sgx_dirty_page_list);
+	left_dirty = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	pr_debug("%ld unsanitized pages\n", left_dirty);
 
-	/* sanity check: */
-	WARN_ON(!list_empty(&sgx_dirty_page_list));
+	left_dirty = __sgx_sanitize_pages(&sgx_dirty_page_list);
+	/*
+	 * Never expected to happen in a working driver. If it happens the bug
+	 * is expected to be in the sanitization process, but successfully
+	 * sanitized pages are still valid and driver can be used and most
+	 * importantly debugged without issues. To put short, the global state
+	 * of kernel is not corrupted so no reason to do any more complicated
+	 * rollback.
+	 */
+	if (ret)
+		pr_err("%ld unsanitized pages\n", left_dirty);
 
 	while (!kthread_should_stop()) {
 		if (try_to_freeze())
Signature · 1 line
2.37.2
author maintainer
#12 lore raw

Re: [PATCH v2 2/6] x86/sgx: Do not consider unsanitized pages an error

arch/x86/kernel/cpu/sgx/main.c void sgx_reclaim_direct(void) · line 420

Quoted 2 lines · Jarkko Sakkinen
arch/x86/kernel/cpu/sgx/main.c +2 -0
+	if (ret)
+		pr_err("%ld unsanitized pages\n", left_dirty);

Yeah, I know, should be 'left_dirty'. I just quickly drafted the patch for the email.

BR, Jarkko

#13 lore raw

Re: [PATCH v2 2/6] x86/sgx: Do not consider unsanitized pages an error

Hi Jarkko,

Quoted 7 lines · Jarkko Sakkinen

arch/x86/kernel/cpu/sgx/main.c void sgx_reclaim_direct(void) · line 420

Quoted 2 lines · Jarkko Sakkinen
arch/x86/kernel/cpu/sgx/main.c +2 -0
+	if (ret)
+		pr_err("%ld unsanitized pages\n", left_dirty);

Yeah, I know, should be 'left_dirty'. I just quickly drafted the patch for the email.

No problem - you did mention that it was an informal patch.

(btw ... also watch out for the long local parameter returned as an unsigned long and the signed vs unsigned printing format string.) I also continue to recommend that you trim that backtrace ... this patch is heading to x86 area where this is required.

Reinette

author maintainer
#14 lore raw

Re: [PATCH v2 2/6] x86/sgx: Do not consider unsanitized pages an error

Quoted 11 lines · Reinette Chatre

Hi Jarkko,

Quoted 7 lines · Jarkko Sakkinen

arch/x86/kernel/cpu/sgx/main.c void sgx_reclaim_direct(void) · line 420

Quoted 2 lines · Jarkko Sakkinen
arch/x86/kernel/cpu/sgx/main.c +2 -0
+	if (ret)
+		pr_err("%ld unsanitized pages\n", left_dirty);

Yeah, I know, should be 'left_dirty'. I just quickly drafted the patch for the email.

Quoted 5 lines

No problem - you did mention that it was an informal patch.

(btw ... also watch out for the long local parameter returned as an unsigned long and the signed vs unsigned printing format string.) I also continue to recommend that you trim

Point taken.

Quoted 2 lines

that backtrace ... this patch is heading to x86 area where this is required.

Should I just cut the whole stack trace, and leave the part before it?

BR, Jarkko

#15 lore raw

Re: [PATCH v2 2/6] x86/sgx: Do not consider unsanitized pages an error

Hi Jarkko,

Quoted 18 lines · Jarkko Sakkinen
Quoted 11 lines · Reinette Chatre

Hi Jarkko,

Quoted 7 lines · Jarkko Sakkinen

arch/x86/kernel/cpu/sgx/main.c void sgx_reclaim_direct(void) · line 420

Quoted 2 lines · Jarkko Sakkinen
arch/x86/kernel/cpu/sgx/main.c +2 -0
+	if (ret)
+		pr_err("%ld unsanitized pages\n", left_dirty);

Yeah, I know, should be 'left_dirty'. I just quickly drafted the patch for the email.

Quoted 5 lines

No problem - you did mention that it was an informal patch.

(btw ... also watch out for the long local parameter returned as an unsigned long and the signed vs unsigned printing format string.) I also continue to recommend that you trim

Quoted 7 lines

Point taken.

Quoted 2 lines

that backtrace ... this patch is heading to x86 area where this is required.

Should I just cut the whole stack trace, and leave the part before it?

The trace is printed because of a WARN_ON() in the code. I do not think there is anything very helpful in that trace. I think the only helpful parts are the WARN itself that includes the line number and then information on which kernel it was encountered on.

How about something like (please note the FIXME within):

"
Paul reported the following WARN while running kernel vFIXME:

  WARNING: CPU: 6 PID: 83 at arch/x86/kernel/cpu/sgx/main.c:401 ksgxd+0x1b7/0x1d0

This is the WARN_ON() within ksgxd() that is triggered when sgx_dirty_page_list (the list containing unsanitized pages) is non-empty.

In sgx_init(), if misc_register() fails or misc_register() succeeds but neither sgx_drv_init() nor sgx_vepc_init() succeeds, then ksgxd will be prematurely stopped. This may leave some unsanitized pages, which does not matter, because SGX will be disabled for the whole power cycle.

Ultimately this can crash the kernel, if the following is set:

/proc/sys/kernel/panic_on_warn

In premature stop, print nothing, as the number is by practical means a random number. Otherwise, it is an indicator of a bug in the driver, and therefore print the number of unsanitized pages with pr_err(). "

Reinette

author maintainer
#16 lore raw

Re: [PATCH v2 2/6] x86/sgx: Do not consider unsanitized pages an error

Quoted 35 lines · Reinette Chatre

Hi Jarkko,

Quoted 18 lines · Jarkko Sakkinen
Quoted 11 lines · Reinette Chatre

Hi Jarkko,

Quoted 7 lines · Jarkko Sakkinen

arch/x86/kernel/cpu/sgx/main.c void sgx_reclaim_direct(void) · line 420

Quoted 2 lines · Jarkko Sakkinen
arch/x86/kernel/cpu/sgx/main.c +2 -0
+	if (ret)
+		pr_err("%ld unsanitized pages\n", left_dirty);

Yeah, I know, should be 'left_dirty'. I just quickly drafted the patch for the email.

Quoted 5 lines

No problem - you did mention that it was an informal patch.

(btw ... also watch out for the long local parameter returned as an unsigned long and the signed vs unsigned printing format string.) I also continue to recommend that you trim

Quoted 7 lines

Point taken.

Quoted 2 lines

that backtrace ... this patch is heading to x86 area where this is required.

Should I just cut the whole stack trace, and leave the part before it?

The trace is printed because of a WARN_ON() in the code. I do not think there is anything very helpful in that trace. I think the only helpful parts are the WARN itself that includes the line number and then information on which kernel it was encountered on.

Quoted 5 lines

How about something like (please note the FIXME within):

"
Paul reported the following WARN while running kernel vFIXME:

  WARNING: CPU: 6 PID: 83 at arch/x86/kernel/cpu/sgx/main.c:401 ksgxd+0x1b7/0x1d0

Yeah, this is a great idea, the use of WARN() is the whole point. Thank you.

BR, Jarkko

author maintainer
#17 lore raw

PATCH v2 3/6 x86/sgx: Handle VA page allocation failure for EAUG on PF.

In reply to Jarkko Sakkinen

From: Haitao Huang <[email protected]>

VM_FAULT_NOPAGE is expected behaviour for -EBUSY failure path, when augmenting a page, as this means that the reclaimer thread has been triggered, and the intention is just to round-trip in ring-3, and retry with a new page fault.

Fixes 5a90d2c3f5ef ("x86/sgx: Support adding of pages to an initialized enclave")

---
v3:
* Added Reinette's ack.

v2:
* Removed reviewed-by, no other changes.

---
 arch/x86/kernel/cpu/sgx/encl.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
arch/x86/kernel/cpu/sgx/encl.c +4 -1
index f40d64206ded..c0fd98a1c658 100644
@@ -347,8 +347,11 @@ static vm_fault_t sgx_encl_eaug_page(struct vm_area_struct *vma,
 	}
 
 	va_page = sgx_encl_grow(encl, false);
-	if (IS_ERR(va_page))
+	if (IS_ERR(va_page)) {
+		if (PTR_ERR(va_page) == -EBUSY)
+			vmret =  VM_FAULT_NOPAGE;
 		goto err_out_epc;
+	}
 
 	if (va_page)
 		list_add(&va_page->list, &encl->va_pages);
Signature · 1 line
2.37.2
#18 lore raw

Re: [PATCH v2 3/6] x86/sgx: Handle VA page allocation failure for EAUG on PF.

Hi Jarkko,

Quoted 7 lines · Jarkko Sakkinen

From: Haitao Huang <[email protected]>

VM_FAULT_NOPAGE is expected behaviour for -EBUSY failure path, when augmenting a page, as this means that the reclaimer thread has been triggered, and the intention is just to round-trip in ring-3, and retry with a new page fault.

Quoted 8 lines
Fixes 5a90d2c3f5ef ("x86/sgx: Support adding of pages to an initialized enclave")

---
v3:
* Added Reinette's ack.

The ack came with a caveat related to a white space issue that you did not fix in this version.

Reinette

author maintainer
#19 lore raw

Re: [PATCH v2 3/6] x86/sgx: Handle VA page allocation failure for EAUG on PF.

Quoted 19 lines · Reinette Chatre

Hi Jarkko,

Quoted 7 lines · Jarkko Sakkinen

From: Haitao Huang <[email protected]>

VM_FAULT_NOPAGE is expected behaviour for -EBUSY failure path, when augmenting a page, as this means that the reclaimer thread has been triggered, and the intention is just to round-trip in ring-3, and retry with a new page fault.

Quoted 8 lines
Fixes 5a90d2c3f5ef ("x86/sgx: Support adding of pages to an initialized enclave")

---
v3:
* Added Reinette's ack.

Quoted 2 lines

The ack came with a caveat related to a white space issue that you did not fix in this version.

Reinette, I'm sorry but I might possibly have some sort of blind spot here.

I looked at the diff and I could not see any issues, and did not run into issues with checkpath.

Can you point out what exactly is the whitespace issue?

BR, Jarkko

#20 lore raw

Re: [PATCH v2 3/6] x86/sgx: Handle VA page allocation failure for EAUG on PF.

Hi Jarkko,

Quoted 2 lines · Jarkko Sakkinen

Can you point out what exactly is the whitespace issue?

There is an extra space after the "=" in:

       vmret =  VM_FAULT_NOPAGE;

Reinette

author maintainer
#21 lore raw

Re: [PATCH v2 3/6] x86/sgx: Handle VA page allocation failure for EAUG on PF.

Quoted 8 lines · Reinette Chatre

Hi Jarkko,

Quoted 2 lines · Jarkko Sakkinen

Can you point out what exactly is the whitespace issue?

There is an extra space after the "=" in:

       vmret =  VM_FAULT_NOPAGE;

Duh, I did look at it about million times but honestly did not see it before you pointed it out.

BR, Jarkko

author maintainer
#22 lore raw

PATCH v2 4/6 selftests/sgx: Add SGX selftest augment_via_eaccept_long

In reply to Jarkko Sakkinen

From: Vijay Dhanraj <[email protected]>

Add a new test case which is same as augment_via_eaccept but adds a larger number of EPC pages to stress test EAUG via EACCEPT.

---
v3:
- Addressed Reinette's feedback:
https://lore.kernel.org/linux-sgx/[email protected]/
v2:
- Addressed Reinette's feedback:
https://lore.kernel.org/linux-sgx/[email protected]/

---
 tools/testing/selftests/sgx/load.c |   5 +-
 tools/testing/selftests/sgx/main.c | 143 +++++++++++++++++++++++++----
 tools/testing/selftests/sgx/main.h |   3 +-
 3 files changed, 130 insertions(+), 21 deletions(-)
tools/testing/selftests/sgx/load.c +3 -2
index 94bdeac1cf04..47b2786d6a77 100644
@@ -171,7 +171,8 @@ uint64_t encl_get_entry(struct encl *encl, const char *symbol)
 	return 0;
 }
 
-bool encl_load(const char *path, struct encl *encl, unsigned long heap_size)
+bool encl_load(const char *path, struct encl *encl, unsigned long heap_size,
+	       unsigned long edmm_size)
 {
 	const char device_path[] = "/dev/sgx_enclave";
 	struct encl_segment *seg;
@@ -300,7 +301,7 @@ bool encl_load(const char *path, struct encl *encl, unsigned long heap_size)
 
 	encl->src_size = encl->segment_tbl[j].offset + encl->segment_tbl[j].size;
 
-	for (encl->encl_size = 4096; encl->encl_size < encl->src_size; )
+	for (encl->encl_size = 4096; encl->encl_size < encl->src_size + edmm_size;)
 		encl->encl_size <<= 1;
 
 	return true;
tools/testing/selftests/sgx/main.c +125 -18

263 lines not on this page · raw message

tools/testing/selftests/sgx/main.h +2 -1
index fc585be97e2f..5c190e21a5ff 100644
@@ -35,7 +35,8 @@ extern unsigned char sign_key[];
 extern unsigned char sign_key_end[];
 
 void encl_delete(struct encl *ctx);
-bool encl_load(const char *path, struct encl *encl, unsigned long heap_size);
+bool encl_load(const char *path, struct encl *encl, unsigned long heap_size,
+	       unsigned long edmm_size);
 bool encl_measure(struct encl *encl);
 bool encl_build(struct encl *encl);
 uint64_t encl_get_entry(struct encl *encl, const char *symbol);
Signature · 1 line
2.37.2
#23 lore raw

Re: [PATCH v2 4/6] selftests/sgx: Add SGX selftest augment_via_eaccept_long

Hi Jarkko,

Quoted 15 lines · Jarkko Sakkinen

From: Vijay Dhanraj <[email protected]>

Add a new test case which is same as augment_via_eaccept but adds a larger number of EPC pages to stress test EAUG via EACCEPT.

---
v3:
- Addressed Reinette's feedback:
https://lore.kernel.org/linux-sgx/[email protected]/
v2:
- Addressed Reinette's feedback:
https://lore.kernel.org/linux-sgx/[email protected]/

Quoted 4 lines
---
 tools/testing/selftests/sgx/load.c |   5 +-
 tools/testing/selftests/sgx/main.c | 143 +++++++++++++++++++++++++----
 tools/testing/selftests/sgx/main.h |   3 +-

Is this test passing on your system? This version is missing the change to mrenclave_ecreate() that causes SGX_IOC_ENCLAVE_INIT to fail when I try it out.

Quoted 30 lines
 3 files changed, 130 insertions(+), 21 deletions(-)
tools/testing/selftests/sgx/load.c +3 -2
index 94bdeac1cf04..47b2786d6a77 100644
@@ -171,7 +171,8 @@ uint64_t encl_get_entry(struct encl *encl, const char *symbol)
 	return 0;
 }
 
-bool encl_load(const char *path, struct encl *encl, unsigned long heap_size)
+bool encl_load(const char *path, struct encl *encl, unsigned long heap_size,
+	       unsigned long edmm_size)
 {
 	const char device_path[] = "/dev/sgx_enclave";
 	struct encl_segment *seg;
@@ -300,7 +301,7 @@ bool encl_load(const char *path, struct encl *encl, unsigned long heap_size)
 
 	encl->src_size = encl->segment_tbl[j].offset + encl->segment_tbl[j].size;
 
-	for (encl->encl_size = 4096; encl->encl_size < encl->src_size; )
+	for (encl->encl_size = 4096; encl->encl_size < encl->src_size + edmm_size;)
 		encl->encl_size <<= 1;
 
 	return true;
tools/testing/selftests/sgx/main.c +0 -0
index 9820b3809c69..c5aa9f323745 100644

tools/testing/selftests/sgx/main.c line 29

Quoted 7 lines
tools/testing/selftests/sgx/main.c +4 -0
@@ -23,6 +23,10 @@
 
 static const uint64_t MAGIC = 0x1122334455667788ULL;
 static const uint64_t MAGIC2 = 0x8877665544332211ULL;
+/* Message-ID: <DM8PR11MB55912A7F47A84EC9913A6352F6999@DM8PR11MB5591.namprd11.prod.outlook.com> */
+static const uint64_t EDMM_SIZE_LONG = 8L * 1024L * 1024L * 1024L;
+static const uint64_t TIMEOUT_LONG = 900; /* seconds */
+

Apologies if my feedback was vague - I actually think that the comments in V1 added valuable information, it was just the variation in formatting that was distracting.

Reinette

author maintainer
#24 lore raw

Re: [PATCH v2 4/6] selftests/sgx: Add SGX selftest augment_via_eaccept_long

Quoted 23 lines · Reinette Chatre

Hi Jarkko,

Quoted 15 lines · Jarkko Sakkinen

From: Vijay Dhanraj <[email protected]>

Add a new test case which is same as augment_via_eaccept but adds a larger number of EPC pages to stress test EAUG via EACCEPT.

---
v3:
- Addressed Reinette's feedback:
https://lore.kernel.org/linux-sgx/[email protected]/
v2:
- Addressed Reinette's feedback:
https://lore.kernel.org/linux-sgx/[email protected]/

Quoted 4 lines
---
 tools/testing/selftests/sgx/load.c |   5 +-
 tools/testing/selftests/sgx/main.c | 143 +++++++++++++++++++++++++----
 tools/testing/selftests/sgx/main.h |   3 +-
Quoted 2 lines

Is this test passing on your system? This version is missing the change to mrenclave_ecreate() that causes SGX_IOC_ENCLAVE_INIT to fail when I try it out.

I *did* get a pass in my test machine. Hmm... I'll check if the kernel tree was out-of-sync, which could be the reason.

I do not compile kernel on that machine but have the kernel tree for running selftests. So there is a possiblity for a human error. Thanks for pointing this out.

Quoted 32 lines
Quoted 32 lines
 3 files changed, 130 insertions(+), 21 deletions(-)
tools/testing/selftests/sgx/load.c +3 -2
index 94bdeac1cf04..47b2786d6a77 100644
@@ -171,7 +171,8 @@ uint64_t encl_get_entry(struct encl *encl, const char *symbol)
 	return 0;
 }
 
-bool encl_load(const char *path, struct encl *encl, unsigned long heap_size)
+bool encl_load(const char *path, struct encl *encl, unsigned long heap_size,
+	       unsigned long edmm_size)
 {
 	const char device_path[] = "/dev/sgx_enclave";
 	struct encl_segment *seg;
@@ -300,7 +301,7 @@ bool encl_load(const char *path, struct encl *encl, unsigned long heap_size)
 
 	encl->src_size = encl->segment_tbl[j].offset + encl->segment_tbl[j].size;
 
-	for (encl->encl_size = 4096; encl->encl_size < encl->src_size; )
+	for (encl->encl_size = 4096; encl->encl_size < encl->src_size + edmm_size;)
 		encl->encl_size <<= 1;
 
 	return true;
tools/testing/selftests/sgx/main.c +0 -0
index 9820b3809c69..c5aa9f323745 100644
@@ -23,6 +23,10 @@
 
Quoted 9 lines

tools/testing/selftests/sgx/main.c line 29

Quoted 6 lines
tools/testing/selftests/sgx/main.c +4 -0
 static const uint64_t MAGIC = 0x1122334455667788ULL;
 static const uint64_t MAGIC2 = 0x8877665544332211ULL;
+/* Message-ID: <DM8PR11MB55912A7F47A84EC9913A6352F6999@DM8PR11MB5591.namprd11.prod.outlook.com> */
+static const uint64_t EDMM_SIZE_LONG = 8L * 1024L * 1024L * 1024L;
+static const uint64_t TIMEOUT_LONG = 900; /* seconds */
+

Apologies if my feedback was vague - I actually think that the comments in V1 added valuable information, it was just the variation in formatting that was distracting.

IMHO message ID is pretty good reference. Can you propose how would you redo it to minimize the number of iterations in the series?

Quoted 1 line

Reinette

BR, Jarkko

#25 lore raw

Re: [PATCH v2 4/6] selftests/sgx: Add SGX selftest augment_via_eaccept_long

Hi Jarkko,

Quoted 2 lines · Jarkko Sakkinen
Quoted 1 line · Reinette Chatre

On 8/31/2022 10:38 AM, Jarkko Sakkinen wrote:

...

Quoted 7 lines
Quoted 6 lines
Quoted 3 lines
 tools/testing/selftests/sgx/load.c |   5 +-
 tools/testing/selftests/sgx/main.c | 143 +++++++++++++++++++++++++----
 tools/testing/selftests/sgx/main.h |   3 +-

Is this test passing on your system? This version is missing the change to mrenclave_ecreate() that causes SGX_IOC_ENCLAVE_INIT to fail when I try it out.

Quoted 6 lines

I *did* get a pass in my test machine. Hmm... I'll check if the kernel tree was out-of-sync, which could be the reason.

I do not compile kernel on that machine but have the kernel tree for running selftests. So there is a possiblity for a human error. Thanks for pointing this out.

On my system I encounter the failure below (V1 of this series did not have this problem):

[SNIP]
ok 11 enclave.augment_via_eaccept
# RUN enclave.augment_via_eaccept_long ...
SGX_IOC_ENCLAVE_INIT failed: Operation not permitted
# main.c:236:augment_via_eaccept_long:0x0000000000000000 0x0000000000002000 0x03
# main.c:236:augment_via_eaccept_long:0x0000000000002000 0x0000000000001000 0x05
# main.c:236:augment_via_eaccept_long:0x0000000000003000 0x0000000000006000 0x03
# main.c:236:augment_via_eaccept_long:0x0000000000009000 0x0000000000001000 0x03
# main.c:251:augment_via_eaccept_long:Failed to initialize the test enclave.
# main.c:1260:augment_via_eaccept_long:Expected 0 (0) != setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata, EDMM_SIZE_LONG) (0) # augment_via_eaccept_long: Test terminated by assertion
# FAIL enclave.augment_via_eaccept_long
not ok 12 enclave.augment_via_eaccept_long
[SNIP]

...

Quoted 11 lines
Quoted 10 lines

tools/testing/selftests/sgx/main.c line 29

Quoted 7 lines

static const uint64_t MAGIC = 0x1122334455667788ULL; static const uint64_t MAGIC2 = 0x8877665544332211ULL;

tools/testing/selftests/sgx/main.c +4 -0
+/* Message-ID: <DM8PR11MB55912A7F47A84EC9913A6352F6999@DM8PR11MB5591.namprd11.prod.outlook.com> */
+static const uint64_t EDMM_SIZE_LONG = 8L * 1024L * 1024L * 1024L;
+static const uint64_t TIMEOUT_LONG = 900; /* seconds */
+

Apologies if my feedback was vague - I actually think that the comments in V1 added valuable information, it was just the variation in formatting that was distracting.

Quoted 3 lines

IMHO message ID is pretty good reference. Can you propose how would you redo it to minimize the number of iterations in the series?

The message ID is a good reference but it points to an email thread and as used here it is unclear what part of that thread is referred to. What you had in V1 was very helpful so it could be:

/*
* The size was chosen based on a bug report:
* Message-ID: <DM8PR11MB55912A7F47A84EC9913A6352F6999@DM8PR11MB5591.namprd11.prod.outlook.com> */

I am not sure about Message-ID vs url. The latter may be more convenient since the user needs to first search which inbox the message-ID belongs to before the message can be accessed. Not a big deal though so I think either works.

Reinette

author maintainer
#26 lore raw

Re: [PATCH v2 4/6] selftests/sgx: Add SGX selftest augment_via_eaccept_long

Quoted 66 lines · Reinette Chatre

Hi Jarkko,

Quoted 2 lines · Jarkko Sakkinen
Quoted 1 line · Reinette Chatre

On 8/31/2022 10:38 AM, Jarkko Sakkinen wrote:

...

Quoted 7 lines
Quoted 6 lines
Quoted 3 lines
 tools/testing/selftests/sgx/load.c |   5 +-
 tools/testing/selftests/sgx/main.c | 143 +++++++++++++++++++++++++----
 tools/testing/selftests/sgx/main.h |   3 +-

Is this test passing on your system? This version is missing the change to mrenclave_ecreate() that causes SGX_IOC_ENCLAVE_INIT to fail when I try it out.

Quoted 6 lines

I *did* get a pass in my test machine. Hmm... I'll check if the kernel tree was out-of-sync, which could be the reason.

I do not compile kernel on that machine but have the kernel tree for running selftests. So there is a possiblity for a human error. Thanks for pointing this out.

On my system I encounter the failure below (V1 of this series did not have this problem):

[SNIP]
ok 11 enclave.augment_via_eaccept
# RUN enclave.augment_via_eaccept_long ...
SGX_IOC_ENCLAVE_INIT failed: Operation not permitted
# main.c:236:augment_via_eaccept_long:0x0000000000000000 0x0000000000002000 0x03
# main.c:236:augment_via_eaccept_long:0x0000000000002000 0x0000000000001000 0x05
# main.c:236:augment_via_eaccept_long:0x0000000000003000 0x0000000000006000 0x03
# main.c:236:augment_via_eaccept_long:0x0000000000009000 0x0000000000001000 0x03
# main.c:251:augment_via_eaccept_long:Failed to initialize the test enclave.
# main.c:1260:augment_via_eaccept_long:Expected 0 (0) != setup_test_encl(ENCL_HEAP_SIZE_DEFAULT, &self->encl, _metadata, EDMM_SIZE_LONG) (0) # augment_via_eaccept_long: Test terminated by assertion
# FAIL enclave.augment_via_eaccept_long
not ok 12 enclave.augment_via_eaccept_long
[SNIP]

...

Quoted 11 lines
Quoted 10 lines

tools/testing/selftests/sgx/main.c line 29

Quoted 7 lines

static const uint64_t MAGIC = 0x1122334455667788ULL; static const uint64_t MAGIC2 = 0x8877665544332211ULL;

tools/testing/selftests/sgx/main.c +4 -0
+/* Message-ID: <DM8PR11MB55912A7F47A84EC9913A6352F6999@DM8PR11MB5591.namprd11.prod.outlook.com> */
+static const uint64_t EDMM_SIZE_LONG = 8L * 1024L * 1024L * 1024L;
+static const uint64_t TIMEOUT_LONG = 900; /* seconds */
+

Apologies if my feedback was vague - I actually think that the comments in V1 added valuable information, it was just the variation in formatting that was distracting.

Quoted 3 lines

IMHO message ID is pretty good reference. Can you propose how would you redo it to minimize the number of iterations in the series?

The message ID is a good reference but it points to an email thread and as used here it is unclear what part of that thread is referred to. What you had in V1 was very helpful so it could be:

/*
* The size was chosen based on a bug report:
* Message-ID: <DM8PR11MB55912A7F47A84EC9913A6352F6999@DM8PR11MB5591.namprd11.prod.outlook.com> */

Quoted 4 lines

I am not sure about Message-ID vs url. The latter may be more convenient since the user needs to first search which inbox the message-ID belongs to before the message can be accessed. Not a big deal though so I think either works.

This is definitely better, I'll use it. Thanks.

Quoted 2 lines

Reinette

BR, Jarkko

author maintainer
#27 lore raw

Re: [PATCH v2 4/6] selftests/sgx: Add SGX selftest augment_via_eaccept_long

In reply to Jarkko Sakkinen
Quoted 9 lines · Jarkko Sakkinen
Quoted 2 lines

Is this test passing on your system? This version is missing the change to mrenclave_ecreate() that causes SGX_IOC_ENCLAVE_INIT to fail when I try it out.

I *did* get a pass in my test machine. Hmm... I'll check if the kernel tree was out-of-sync, which could be the reason.

I do not compile kernel on that machine but have the kernel tree for running selftests. So there is a possiblity for a human error. Thanks for pointing this out.

Apparently, v1 and v2 break the encl->src_size calculation:
the dynamic heap size is not added.

So, in order to revert sigstruct change:

tools/testing/selftests/sgx/load.c +3 -3
index 47b2786d6a77..0e4e12e1e3eb 100644
@@ -172,7 +172,7 @@ uint64_t encl_get_entry(struct encl *encl, const char *symbol)
 }
 
 bool encl_load(const char *path, struct encl *encl, unsigned long heap_size,
-              unsigned long edmm_size)
+              unsigned long dynamic_heap_size)
 {
        const char device_path[] = "/dev/sgx_enclave";
        struct encl_segment *seg;
@@ -299,9 +299,9 @@ bool encl_load(const char *path, struct encl *encl, unsigned long heap_size,
        if (seg->src == MAP_FAILED)
                goto err;
 
-       encl->src_size = encl->segment_tbl[j].offset + encl->segment_tbl[j].size;
+       encl->src_size = encl->segment_tbl[j].offset + encl->segment_tbl[j].size + dynamic_heap_size;
 
-       for (encl->encl_size = 4096; encl->encl_size < encl->src_size + edmm_size;)
+       for (encl->encl_size = 4096; encl->encl_size < encl->src_size;)
                encl->encl_size <<= 1;
 
        return true;

BR, Jarkko

author maintainer
#28 lore raw

Re: [PATCH v2 4/6] selftests/sgx: Add SGX selftest augment_via_eaccept_long

Quoted 30 lines · Jarkko Sakkinen
Quoted 9 lines · Jarkko Sakkinen
Quoted 2 lines

Is this test passing on your system? This version is missing the change to mrenclave_ecreate() that causes SGX_IOC_ENCLAVE_INIT to fail when I try it out.

I *did* get a pass in my test machine. Hmm... I'll check if the kernel tree was out-of-sync, which could be the reason.

I do not compile kernel on that machine but have the kernel tree for running selftests. So there is a possiblity for a human error. Thanks for pointing this out.

Apparently, v1 and v2 break the encl->src_size calculation:
the dynamic heap size is not added.

So, in order to revert sigstruct change:

tools/testing/selftests/sgx/load.c +1 -1
index 47b2786d6a77..0e4e12e1e3eb 100644
@@ -172,7 +172,7 @@ uint64_t encl_get_entry(struct encl *encl, const char *symbol)
 }
 
 bool encl_load(const char *path, struct encl *encl, unsigned long heap_size,
-              unsigned long edmm_size)
+              unsigned long dynamic_heap_size)
 {
        const char device_path[] = "/dev/sgx_enclave";
        struct encl_segment *seg;

tools/testing/selftests/sgx/load.c bool encl_load(const char *path, struct encl *encl, unsigned long heap_size, · line 305

Quoted 9 lines
tools/testing/selftests/sgx/load.c +2 -2
@@ -299,9 +299,9 @@ bool encl_load(const char *path, struct encl *encl, unsigned long heap_size,
        if (seg->src == MAP_FAILED)
                goto err;
 
-       encl->src_size = encl->segment_tbl[j].offset + encl->segment_tbl[j].size;
+       encl->src_size = encl->segment_tbl[j].offset + encl->segment_tbl[j].size + dynamic_heap_size;
 
-       for (encl->encl_size = 4096; encl->encl_size < encl->src_size + edmm_size;)
+       for (encl->encl_size = 4096; encl->encl_size < encl->src_size;)
                encl->encl_size <<= 1;

Actually, it is correct after all how Vijay changed it. We should use the final pre-calculated enclave address range in sigstruct.c. It's the re-calculation of that in sigstruct is a reminiscent of it being a separate command-line utility, instead of calculating the sigstruct on-fly. I.e. there has been sane reasons why it has been like that.

BR, Jarkko

author maintainer
#29 lore raw

PATCH v2 5/6 selftests/sgx: retry the ioctls returned with EAGAIN

In reply to Jarkko Sakkinen

From: Haitao Huang <[email protected]>

For EMODT and EREMOVE ioctls with a large range, kernel may not finish in one shot and return EAGAIN error code and count of bytes of EPC pages on that operations are finished successfully.

Change the unclobbered_vdso_oversubscribed_remove test to rerun the ioctls in a loop, updating offset and length using the byte count returned in each iteration.

---
v2:
* Changed branching in EAGAIN condition so that else branch is not required.
* Addressed Reinette's feedback:
https://lore.kernel.org/linux-sgx/[email protected]/

---
 tools/testing/selftests/sgx/main.c | 42 ++++++++++++++++++++++++------
 1 file changed, 34 insertions(+), 8 deletions(-)
tools/testing/selftests/sgx/main.c +34 -8
index c5aa9f323745..f42941da3bbe 100644
@@ -395,6 +395,7 @@ TEST_F_TIMEOUT(enclave, unclobbered_vdso_oversubscribed_remove, 900)
 	struct encl_segment *heap;
 	unsigned long total_mem;
 	int ret, errno_save;
+	unsigned long count;
 	unsigned long addr;
 	unsigned long i;
 
@@ -458,16 +459,30 @@ TEST_F_TIMEOUT(enclave, unclobbered_vdso_oversubscribed_remove, 900)
 	modt_ioc.offset = heap->offset;
 	modt_ioc.length = heap->size;
 	modt_ioc.page_type = SGX_PAGE_TYPE_TRIM;
-
+	count = 0;
 	TH_LOG("Changing type of %zd bytes to trimmed may take a while ...",
 	       heap->size);
-	ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);
-	errno_save = ret == -1 ? errno : 0;
+	do {
+		ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);
+
+		errno_save = ret == -1 ? errno : 0;
+		if (errno_save != EAGAIN)
+			break;
+
+		EXPECT_EQ(modt_ioc.result, 0);
+
+		count += modt_ioc.count;
+		modt_ioc.offset += modt_ioc.count;
+		modt_ioc.length -= modt_ioc.count;
+		modt_ioc.result = 0;
+		modt_ioc.count = 0;
+	} while (modt_ioc.length != 0);
 
 	EXPECT_EQ(ret, 0);
 	EXPECT_EQ(errno_save, 0);
 	EXPECT_EQ(modt_ioc.result, 0);
-	EXPECT_EQ(modt_ioc.count, heap->size);
+	count += modt_ioc.count;
+	EXPECT_EQ(count, heap->size);
 
 	/* EACCEPT all removed pages. */
 	addr = self->encl.encl_base + heap->offset;
@@ -495,15 +510,26 @@ TEST_F_TIMEOUT(enclave, unclobbered_vdso_oversubscribed_remove, 900)
 
 	remove_ioc.offset = heap->offset;
 	remove_ioc.length = heap->size;
-
+	count = 0;
 	TH_LOG("Removing %zd bytes from enclave may take a while ...",
 	       heap->size);
-	ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc);
-	errno_save = ret == -1 ? errno : 0;
+	do {
+		ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_REMOVE_PAGES, &remove_ioc);
+
+		errno_save = ret == -1 ? errno : 0;
+		if (errno_save != EAGAIN)
+			break;
+
+		count += remove_ioc.count;
+		remove_ioc.offset += remove_ioc.count;
+		remove_ioc.length -= remove_ioc.count;
+		remove_ioc.count = 0;
+	} while (remove_ioc.length != 0);
 
 	EXPECT_EQ(ret, 0);
 	EXPECT_EQ(errno_save, 0);
-	EXPECT_EQ(remove_ioc.count, heap->size);
+	count += remove_ioc.count;
+	EXPECT_EQ(count, heap->size);
 }
 
 TEST_F(enclave, clobbered_vdso)
Signature · 1 line
2.37.2
#30 lore raw

Re: [PATCH v2 5/6] selftests/sgx: retry the ioctls returned with EAGAIN

Hi Jarkko,

Quoted 13 lines · Jarkko Sakkinen
tools/testing/selftests/sgx/main.c +4 -3
@@ -458,16 +459,30 @@ TEST_F_TIMEOUT(enclave, unclobbered_vdso_oversubscribed_remove, 900)
 	modt_ioc.offset = heap->offset;
 	modt_ioc.length = heap->size;
 	modt_ioc.page_type = SGX_PAGE_TYPE_TRIM;
-
+	count = 0;
 	TH_LOG("Changing type of %zd bytes to trimmed may take a while ...",
 	       heap->size);
-	ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);
-	errno_save = ret == -1 ? errno : 0;
+	do {
+		ret = ioctl(self->encl.fd, SGX_IOC_ENCLAVE_MODIFY_TYPES, &modt_ioc);
+

tools/testing/selftests/sgx/main.c TEST_F_TIMEOUT(enclave, unclobbered_vdso_oversubscribed_remove, 900) · line 477

Quoted 10 lines
tools/testing/selftests/sgx/main.c +10 -0
+		errno_save = ret == -1 ? errno : 0;
+		if (errno_save != EAGAIN)
+			break;
+
+		EXPECT_EQ(modt_ioc.result, 0);
+
+		count += modt_ioc.count;
+		modt_ioc.offset += modt_ioc.count;
+		modt_ioc.length -= modt_ioc.count;
+		modt_ioc.result = 0;

From the discussion in V1 it seemed that you were planning to add a check on the result value instead of just overwriting it. Are you still planning to do this?

Reinette

author maintainer
#31 lore raw

PATCH v2 6/6 selftests/sgx: Add a bpftrace script for tracking allocation errors

In reply to Jarkko Sakkinen

---
v2:
* Added comments.

---
 tools/testing/selftests/sgx/alloc-error.bt | 9 +++++++++
 1 file changed, 9 insertions(+)
 create mode 100644 tools/testing/selftests/sgx/alloc-error.bt
tools/testing/selftests/sgx/alloc-error.bt new file +9 -0
new file mode 100644
index 000000000000..0cc8b2e41852
@@ -0,0 +1,9 @@
+/* EPC allocation */
+kr:sgx_alloc_epc_page /(uint64)retval >= (uint64)(-4095)/ {
+		 printf("sgx_alloc_epc_page: retval=%d\n", (int64)retval);
+}
+
+/* kzalloc for struct sgx_encl_page */
+kr:sgx_encl_page_alloc /(uint64)retval >= (uint64)(-4095)/ {
+		 printf("sgx_encl_page_alloc: retval=%d\n", (int64)retval);
+}
Signature · 1 line
2.37.2
#32 lore raw

Re: [PATCH v2 6/6] selftests/sgx: Add a bpftrace script for tracking allocation errors

Hi Jarkko,

Quoted 15 lines · Jarkko Sakkinen

---
v2:
* Added comments.

---
 tools/testing/selftests/sgx/alloc-error.bt | 9 +++++++++
 1 file changed, 9 insertions(+)
 create mode 100644 tools/testing/selftests/sgx/alloc-error.bt
tools/testing/selftests/sgx/alloc-error.bt new file +0 -0
new file mode 100644
index 000000000000..0cc8b2e41852

tools/testing/selftests/sgx/alloc-error.bt line 9

Quoted 9 lines
tools/testing/selftests/sgx/alloc-error.bt new file +9 -0
@@ -0,0 +1,9 @@
+/* EPC allocation */
+kr:sgx_alloc_epc_page /(uint64)retval >= (uint64)(-4095)/ {
+		 printf("sgx_alloc_epc_page: retval=%d\n", (int64)retval);
+}
+
+/* kzalloc for struct sgx_encl_page */
+kr:sgx_encl_page_alloc /(uint64)retval >= (uint64)(-4095)/ {
+		 printf("sgx_encl_page_alloc: retval=%d\n", (int64)retval);
+}

I did see you response in [1]. I continue to find this addition very cryptic in that it assumes global familiarity with BPF scripting which I do not think can be assumed. I still think this script can benefit from a comment to describe what the script does and how to use it.

Reinette

[1] https://lore.kernel.org/linux-sgx/[email protected]/

author maintainer
#33 lore raw

Re: [PATCH v2 6/6] selftests/sgx: Add a bpftrace script for tracking allocation errors

Quoted 25 lines · Reinette Chatre

Hi Jarkko,

Quoted 22 lines · Jarkko Sakkinen

---
v2:
* Added comments.

---
 tools/testing/selftests/sgx/alloc-error.bt | 9 +++++++++
 1 file changed, 9 insertions(+)
 create mode 100644 tools/testing/selftests/sgx/alloc-error.bt
tools/testing/selftests/sgx/alloc-error.bt new file +7 -0
new file mode 100644
index 000000000000..0cc8b2e41852
@@ -0,0 +1,9 @@
+/* EPC allocation */
+kr:sgx_alloc_epc_page /(uint64)retval >= (uint64)(-4095)/ {
+		 printf("sgx_alloc_epc_page: retval=%d\n", (int64)retval);
+}
+
+/* kzalloc for struct sgx_encl_page */
+kr:sgx_encl_page_alloc /(uint64)retval >= (uint64)(-4095)/ {
Quoted 8 lines

tools/testing/selftests/sgx/alloc-error.bt line 9

Quoted 2 lines
tools/testing/selftests/sgx/alloc-error.bt new file +2 -0
+		 printf("sgx_encl_page_alloc: retval=%d\n", (int64)retval);
+}

I did see you response in [1]. I continue to find this addition very cryptic in that it assumes global familiarity with BPF scripting which I do not think can be assumed. I still think this script can benefit from a comment to describe what the script does and how to use it.

I think I follow Dave's advice to use perf here. I'll make a header which explains what the script does.

BR, Jarkko

#34 lore raw
In reply to Jarkko Sakkinen

Jarkko,

What is your expectations of this series? There's nothing in the cover letter.

Do you think all of this is urgent material that needs to go to Linus for 6.0? Or is it all 6.1 material?

author maintainer
#35 lore raw
Quoted 7 lines · Dave Hansen

Jarkko,

What is your expectations of this series? There's nothing in the cover letter.

Do you think all of this is urgent material that needs to go to Linus for 6.0? Or is it all 6.1 material?

Hmm... Let me think.

I would pick exactly 2/6 and 3/6 and postpone rest for 6.1.

2/6 is IMHO critical fix and 3/6 is fix for a commit that is part of 6.0.

BR, Jarkko

#36 lore raw
Quoted 6 lines · Jarkko Sakkinen
Quoted 5 lines · Dave Hansen

Jarkko,

What is your expectations of this series? There's nothing in the cover letter.

Quoted 8 lines
Quoted 2 lines

Do you think all of this is urgent material that needs to go to Linus for 6.0? Or is it all 6.1 material?

Hmm... Let me think.

I would pick exactly 2/6 and 3/6 and postpone rest for 6.1.

2/6 is IMHO critical fix and 3/6 is fix for a commit that is part of 6.0.

That's really great context, thanks! Next time, could you please include that in your cover letter(s) and split the patches up between urgent non-urgent bits?

author maintainer
#37 lore raw
Quoted 11 lines · Dave Hansen
Quoted 10 lines · Jarkko Sakkinen
Quoted 7 lines · Dave Hansen

Jarkko,

What is your expectations of this series? There's nothing in the cover letter.

Do you think all of this is urgent material that needs to go to Linus for 6.0? Or is it all 6.1 material?

Hmm... Let me think.

Quoted 8 lines
Quoted 4 lines

I would pick exactly 2/6 and 3/6 and postpone rest for 6.1.

2/6 is IMHO critical fix and 3/6 is fix for a commit that is part of 6.0.

That's really great context, thanks! Next time, could you please include that in your cover letter(s) and split the patches up between urgent non-urgent bits?

I can, no problem.

BR, Jarkko