summary refs log tree commit diff stats
path: root/linux-user/syscall.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2023-07-04 08:36:44 +0200
committerRichard Henderson <richard.henderson@linaro.org>2023-07-04 08:36:44 +0200
commit2a6ae69154542caa91dd17c40fd3f5ffbec300de (patch)
tree137f02613260faea2e771cb0df1d9e896f571a1b /linux-user/syscall.c
parentd145c0da22cde391d8c6672d33146ce306e8bf75 (diff)
parenta6341482695e1d15f11915f12dba98724efb0697 (diff)
downloadfocaccia-qemu-2a6ae69154542caa91dd17c40fd3f5ffbec300de.tar.gz
focaccia-qemu-2a6ae69154542caa91dd17c40fd3f5ffbec300de.zip
Merge tag 'pull-maintainer-ominbus-030723-1' of https://gitlab.com/stsquad/qemu into staging
maintainer updates: testing, fuzz, plugins, docs, gdbstub

 - clean up gitlab artefact handling
 - ensure gitlab publishes artefacts with coverage data
 - reduce testing scope for coverage job
 - mention CI pipeline in developer docs
 - add ability to add plugin args to check-tcg
 - fix some memory leaks and UB in tests
 - suppress xcb leaks from fuzzing output
 - add a test-fuzz to mirror the CI run
 - allow lci-refresh to be run in $SRC
 - update lcitool to latest version
 - add qemu-minimal package set with gcc-native
 - convert riscv64-cross to lcitool
 - update sbsa-ref tests
 - don't include arm_casq_ptw emulation unless TCG
 - convert plugins to use g_memdup2
 - ensure plugins instrument SVE helper mem access
 - improve documentation of QOM/QDEV
 - make gdbstub send stop responses when it should
 - report user-mode pid in gdbstub
 - add support for info proc mappings in gdbstub

# -----BEGIN PGP SIGNATURE-----
#
# iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmSiuH4ACgkQ+9DbCVqe
# KkRt0Qf+N0oD/VuEcRSxK1bWlLtf5nxQpPKKzkRItPc5jqJnLWa/gh21sfQgs5Uq
# BczAT+JfgTnMozbq0mjvQ+uAGI4MHzBs+UAn60+ZcXfk2inyk77XKBEoHOFuK1ry
# rgQ4+p21/hcZedDiDLnLSfbGfUU0KkM/pbAegOz7HO0EQDV0CSXqeAW3WAuM1lne
# +YmXkKwoFI1V8HvslzCT12GFiaUfmSSBtASqWcf67Ief97K24+rpkAVM7JChLm5X
# fC1MOFNuNYV+jO+9U3KIs15P1WH12oMcpNUY+KqQ5ZWovBg83yOLtKY1o3f6Z2Y+
# iQgFJr6F8ZVBdKNJtqVi8DkbiFfbsA==
# =Ho/h
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 03 Jul 2023 02:01:02 PM CEST
# gpg:                using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44
# gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 6685 AE99 E751 67BC AFC8  DF35 FBD0 DB09 5A9E 2A44

* tag 'pull-maintainer-ominbus-030723-1' of https://gitlab.com/stsquad/qemu: (38 commits)
  tests/tcg: Add a test for info proc mappings
  docs: Document security implications of debugging
  gdbstub: Add support for info proc mappings
  gdbstub: Report the actual qemu-user pid
  gdbstub: Expose gdb_get_process() and gdb_get_first_cpu_in_process()
  linux-user: Emulate /proc/self/smaps
  linux-user: Add "safe" parameter to do_guest_openat()
  linux-user: Expose do_guest_openat() and do_guest_readlink()
  gdbstub: clean-up vcont handling to avoid goto
  gdbstub: Permit reverse step/break to provide stop response
  gdbstub: lightly refactor connection to avoid snprintf
  docs/devel: introduce some key concepts for QOM development
  docs/devel: split qom-api reference into new file
  docs/devel/qom.rst: Correct code style
  include/hw/qdev-core: fixup kerneldoc annotations
  include/migration: mark vmstate_register() as a legacy function
  docs/devel: add some front matter to the devel index
  plugins: update lockstep to use g_memdup2
  plugins: fix memory leak while parsing options
  plugins: force slow path when plugins instrument memory ops
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'linux-user/syscall.c')
-rw-r--r--linux-user/syscall.c128
1 files changed, 104 insertions, 24 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f2cb101d83..08162cc966 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8042,7 +8042,36 @@ static int open_self_cmdline(CPUArchState *cpu_env, int fd)
     return 0;
 }
 
-static int open_self_maps(CPUArchState *cpu_env, int fd)
+static void show_smaps(int fd, unsigned long size)
+{
+    unsigned long page_size_kb = TARGET_PAGE_SIZE >> 10;
+    unsigned long size_kb = size >> 10;
+
+    dprintf(fd, "Size:                  %lu kB\n"
+                "KernelPageSize:        %lu kB\n"
+                "MMUPageSize:           %lu kB\n"
+                "Rss:                   0 kB\n"
+                "Pss:                   0 kB\n"
+                "Pss_Dirty:             0 kB\n"
+                "Shared_Clean:          0 kB\n"
+                "Shared_Dirty:          0 kB\n"
+                "Private_Clean:         0 kB\n"
+                "Private_Dirty:         0 kB\n"
+                "Referenced:            0 kB\n"
+                "Anonymous:             0 kB\n"
+                "LazyFree:              0 kB\n"
+                "AnonHugePages:         0 kB\n"
+                "ShmemPmdMapped:        0 kB\n"
+                "FilePmdMapped:         0 kB\n"
+                "Shared_Hugetlb:        0 kB\n"
+                "Private_Hugetlb:       0 kB\n"
+                "Swap:                  0 kB\n"
+                "SwapPss:               0 kB\n"
+                "Locked:                0 kB\n"
+                "THPeligible:    0\n", size_kb, page_size_kb, page_size_kb);
+}
+
+static int open_self_maps_1(CPUArchState *cpu_env, int fd, bool smaps)
 {
     CPUState *cpu = env_cpu(cpu_env);
     TaskState *ts = cpu->opaque;
@@ -8089,6 +8118,18 @@ static int open_self_maps(CPUArchState *cpu_env, int fd)
             } else {
                 dprintf(fd, "\n");
             }
+            if (smaps) {
+                show_smaps(fd, max - min);
+                dprintf(fd, "VmFlags:%s%s%s%s%s%s%s%s\n",
+                        (flags & PAGE_READ) ? " rd" : "",
+                        (flags & PAGE_WRITE_ORG) ? " wr" : "",
+                        (flags & PAGE_EXEC) ? " ex" : "",
+                        e->is_priv ? "" : " sh",
+                        (flags & PAGE_READ) ? " mr" : "",
+                        (flags & PAGE_WRITE_ORG) ? " mw" : "",
+                        (flags & PAGE_EXEC) ? " me" : "",
+                        e->is_priv ? "" : " ms");
+            }
         }
     }
 
@@ -8103,11 +8144,25 @@ static int open_self_maps(CPUArchState *cpu_env, int fd)
                     " --xp 00000000 00:00 0",
                     TARGET_VSYSCALL_PAGE, TARGET_VSYSCALL_PAGE + TARGET_PAGE_SIZE);
     dprintf(fd, "%*s%s\n", 73 - count, "",  "[vsyscall]");
+    if (smaps) {
+        show_smaps(fd, TARGET_PAGE_SIZE);
+        dprintf(fd, "VmFlags: ex\n");
+    }
 #endif
 
     return 0;
 }
 
+static int open_self_maps(CPUArchState *cpu_env, int fd)
+{
+    return open_self_maps_1(cpu_env, fd, false);
+}
+
+static int open_self_smaps(CPUArchState *cpu_env, int fd)
+{
+    return open_self_maps_1(cpu_env, fd, true);
+}
+
 static int open_self_stat(CPUArchState *cpu_env, int fd)
 {
     CPUState *cpu = env_cpu(cpu_env);
@@ -8448,7 +8503,8 @@ static int open_hardware(CPUArchState *cpu_env, int fd)
 }
 #endif
 
-static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode)
+int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname,
+                    int flags, mode_t mode, bool safe)
 {
     struct fake_open {
         const char *filename;
@@ -8458,6 +8514,7 @@ static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int
     const struct fake_open *fake_open;
     static const struct fake_open fakes[] = {
         { "maps", open_self_maps, is_proc_myself },
+        { "smaps", open_self_smaps, is_proc_myself },
         { "stat", open_self_stat, is_proc_myself },
         { "auxv", open_self_auxv, is_proc_myself },
         { "cmdline", open_self_cmdline, is_proc_myself },
@@ -8475,7 +8532,11 @@ static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int
     };
 
     if (is_proc_myself(pathname, "exe")) {
-        return safe_openat(dirfd, exec_path, flags, mode);
+        if (safe) {
+            return safe_openat(dirfd, exec_path, flags, mode);
+        } else {
+            return openat(dirfd, exec_path, flags, mode);
+        }
     }
 
     for (fake_open = fakes; fake_open->filename; fake_open++) {
@@ -8517,7 +8578,41 @@ static int do_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int
         return fd;
     }
 
-    return safe_openat(dirfd, path(pathname), flags, mode);
+    if (safe) {
+        return safe_openat(dirfd, path(pathname), flags, mode);
+    } else {
+        return openat(dirfd, path(pathname), flags, mode);
+    }
+}
+
+ssize_t do_guest_readlink(const char *pathname, char *buf, size_t bufsiz)
+{
+    ssize_t ret;
+
+    if (!pathname || !buf) {
+        errno = EFAULT;
+        return -1;
+    }
+
+    if (!bufsiz) {
+        /* Short circuit this for the magic exe check. */
+        errno = EINVAL;
+        return -1;
+    }
+
+    if (is_proc_myself((const char *)pathname, "exe")) {
+        /*
+         * Don't worry about sign mismatch as earlier mapping
+         * logic would have thrown a bad address error.
+         */
+        ret = MIN(strlen(exec_path), bufsiz);
+        /* We cannot NUL terminate the string. */
+        memcpy(buf, exec_path, ret);
+    } else {
+        ret = readlink(path(pathname), buf, bufsiz);
+    }
+
+    return ret;
 }
 
 static int do_execveat(CPUArchState *cpu_env, int dirfd,
@@ -8994,9 +9089,9 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
     case TARGET_NR_open:
         if (!(p = lock_user_string(arg1)))
             return -TARGET_EFAULT;
-        ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
+        ret = get_errno(do_guest_openat(cpu_env, AT_FDCWD, p,
                                   target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                                  arg3));
+                                  arg3, true));
         fd_trans_unregister(ret);
         unlock_user(p, arg1, 0);
         return ret;
@@ -9004,9 +9099,9 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
     case TARGET_NR_openat:
         if (!(p = lock_user_string(arg2)))
             return -TARGET_EFAULT;
-        ret = get_errno(do_openat(cpu_env, arg1, p,
+        ret = get_errno(do_guest_openat(cpu_env, arg1, p,
                                   target_to_host_bitmask(arg3, fcntl_flags_tbl),
-                                  arg4));
+                                  arg4, true));
         fd_trans_unregister(ret);
         unlock_user(p, arg2, 0);
         return ret;
@@ -10229,22 +10324,7 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
             void *p2;
             p = lock_user_string(arg1);
             p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
-            if (!p || !p2) {
-                ret = -TARGET_EFAULT;
-            } else if (!arg3) {
-                /* Short circuit this for the magic exe check. */
-                ret = -TARGET_EINVAL;
-            } else if (is_proc_myself((const char *)p, "exe")) {
-                /*
-                 * Don't worry about sign mismatch as earlier mapping
-                 * logic would have thrown a bad address error.
-                 */
-                ret = MIN(strlen(exec_path), arg3);
-                /* We cannot NUL terminate the string. */
-                memcpy(p2, exec_path, ret);
-            } else {
-                ret = get_errno(readlink(path(p), p2, arg3));
-            }
+            ret = get_errno(do_guest_readlink(p, p2, arg3));
             unlock_user(p2, arg2, ret);
             unlock_user(p, arg1, 0);
         }