Skip to content

Instantly share code, notes, and snippets.

@agentzh
Last active August 18, 2020 06:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save agentzh/7a9095fe5f720a155b3e6eabe6a3fab3 to your computer and use it in GitHub Desktop.
Save agentzh/7a9095fe5f720a155b3e6eabe6a3fab3 to your computer and use it in GitHub Desktop.
diff --git a/runtime/linux/loc2c-runtime.h b/runtime/linux/loc2c-runtime.h
index 0270fa1a0..718b0fc15 100644
--- a/runtime/linux/loc2c-runtime.h
+++ b/runtime/linux/loc2c-runtime.h
@@ -380,6 +380,15 @@ static inline int __stp_deref_nocheck_(u64 *pv, size_t size, void *addr)
{
u64 v = 0;
int r = -EFAULT;
+ struct mm_struct *mm = current->mm;
+
+ if (mm) {
+ // The down_read() function can sleep, so we'll call
+ // down_read_trylock() instead, which can fail.
+ if (! down_read_trylock(&mm->mmap_sem)) {
+ return -EBUSY;
+ }
+ }
switch (size)
{
@@ -400,6 +409,9 @@ static inline int __stp_deref_nocheck_(u64 *pv, size_t size, void *addr)
#endif
}
+ if (mm)
+ up_read(&mm->mmap_sem);
+
*pv = v;
return r;
}
@@ -529,8 +541,12 @@ static inline int _stp_deref_nofault_(u64 *pv, size_t size, void *addr,
default: \
__stp_get_user_bad(); \
} \
- if (_e) \
- DEREF_FAULT(addr); \
+ if (_e) { \
+ if (_e == -EBUSY) \
+ DEREF_BUSY(addr); \
+ else \
+ DEREF_FAULT(addr); \
+ } \
_v; \
})
@@ -773,6 +789,17 @@ static inline long _stp_deref_string_nofault(char *dst, const char *addr,
err = 1;
else
{
+ struct mm_struct *mm = current->mm;
+ if (mm) {
+ // The down_read() function can sleep, so we'll call
+ // down_read_trylock() instead, which can fail.
+ if (! down_read_trylock(&mm->mmap_sem)) {
+ pagefault_enable();
+ set_fs(oldfs);
+ return -EBUSY;
+ }
+ }
+
/* Reduce len by 1 to leave room for '\0' terminator. */
for (i = 0; i + 1 < len; ++i)
{
@@ -783,6 +810,10 @@ static inline long _stp_deref_string_nofault(char *dst, const char *addr,
if (dst)
*dst++ = v;
}
+
+ if (mm)
+ up_read(&mm->mmap_sem);
+
if (!err && dst)
*dst = '\0';
}
diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h
index 0502d5a07..7d5f9c7b1 100644
--- a/runtime/loc2c-runtime.h
+++ b/runtime/loc2c-runtime.h
@@ -232,10 +232,19 @@
#if STP_SKIP_BADVARS
+#define DEREF_BUSY(addr) ({0; })
#define DEREF_FAULT(addr) ({0; })
#define STORE_DEREF_FAULT(addr) ({0; })
#define CATCH_DEREF_FAULT() ({0; })
#else
+#define DEREF_BUSY(addr) ({ \
+ snprintf(c->error_buffer, sizeof(c->error_buffer), \
+ STAP_MSG_LOC2C_00, (int)current->tgid, \
+ (long)(intptr_t)(addr)); \
+ c->last_error = c->error_buffer; \
+ goto deref_fault; \
+ })
+
#define DEREF_FAULT(addr) ({ \
snprintf(c->error_buffer, sizeof(c->error_buffer), \
STAP_MSG_LOC2C_01, (long)(intptr_t)(addr)); \
diff --git a/tapset/uconversions.stp b/tapset/uconversions.stp
index 83790e992..8654821d2 100644
--- a/tapset/uconversions.stp
+++ b/tapset/uconversions.stp
@@ -124,9 +124,14 @@ function user_string_n:string (addr:long, n:long)
(char __user *) (uintptr_t) STAP_ARG_addr, len);
if (rc < 0) {
strlcpy(STAP_RETVALUE, "<unknown>", MAXSTRINGLEN);
- snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer),
- "user string copy fault %ld at 0x%lx [man error::fault]", rc,
- (unsigned long) (uintptr_t) STAP_ARG_addr);
+ if (rc == -EBUSY)
+ snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer),
+ "mm sem busy in user string copy %ld at 0x%lx [man error::fault]", rc,
+ (uintptr_t) STAP_ARG_addr);
+ else
+ snprintf (CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer),
+ "user string copy fault %ld at 0x%lx [man error::fault]", rc,
+ (uintptr_t) STAP_ARG_addr);
CONTEXT->last_error = CONTEXT->error_buffer;
} else
STAP_RETVALUE[len - 1] = '\0';
diff --git a/translate.cxx b/translate.cxx
index a29d9da29..b504066b9 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -7862,6 +7862,8 @@ void translate_runtime(systemtap_session& s)
<< lex_cast_qstring(_("myproc-unprivileged tapset function called "
"without is_myproc checking for pid %d (euid %d)"));
+ s.op->newline() << "#define STAP_MSG_LOC2C_00 "
+ << lex_cast_qstring(_("pid %d: mm sem busy [man error::fault] at 0x%lx"));
s.op->newline() << "#define STAP_MSG_LOC2C_01 "
<< lex_cast_qstring(_("read fault [man error::fault] at 0x%lx"));
s.op->newline() << "#define STAP_MSG_LOC2C_02 "
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment