diff options
author | Benoît Dejean <bdejean@gmail.com> | 2018-03-26 18:14:58 +0200 |
---|---|---|
committer | Benoît Dejean <bdejean@gmail.com> | 2018-03-26 18:15:26 +0200 |
commit | e4335d4db28491c256d80efb63492d83d0560a37 (patch) | |
tree | b36396c2547f2d35cf3599da36b43d37d9856bc8 | |
parent | ec662d01dac16b817981da9ace55230441ef4cd4 (diff) | |
download | libgtop-e4335d4db28491c256d80efb63492d83d0560a37.tar.gz |
glibtop_get_proc_map on Linux doesn't need to be SUID.
Revert this proof of concept.
Add C file with comments to document how to make a call SUID.
-rw-r--r-- | sysdeps/linux/glibtop_server.h | 2 | ||||
-rw-r--r-- | sysdeps/linux/procmap.c | 12 | ||||
-rw-r--r-- | sysdeps/linux/procmap.c.suid_example | 334 |
3 files changed, 337 insertions, 11 deletions
diff --git a/sysdeps/linux/glibtop_server.h b/sysdeps/linux/glibtop_server.h index 75f63160..6240d5de 100644 --- a/sysdeps/linux/glibtop_server.h +++ b/sysdeps/linux/glibtop_server.h @@ -39,7 +39,7 @@ #define GLIBTOP_SUID_PROC_KERNEL 0 #define GLIBTOP_SUID_PROC_SEGMENT 0 #define GLIBTOP_SUID_PROC_ARGS 0 -#define GLIBTOP_SUID_PROC_MAP (1 << GLIBTOP_SYSDEPS_PROC_MAP) +#define GLIBTOP_SUID_PROC_MAP 0 #define GLIBTOP_SUID_NETLOAD 0 #define GLIBTOP_SUID_NETLIST 0 #define GLIBTOP_SUID_PROC_WD 0 diff --git a/sysdeps/linux/procmap.c b/sysdeps/linux/procmap.c index cbbd5c42..546d08af 100644 --- a/sysdeps/linux/procmap.c +++ b/sysdeps/linux/procmap.c @@ -30,7 +30,6 @@ #include <stddef.h> #include "glibtop_private.h" -#include "glibtop_suid.h" #include "procmap_smaps.c" @@ -61,7 +60,7 @@ static const unsigned long _glibtop_sysdeps_map_entry_smaps = /* Init function. */ void -_glibtop_init_proc_map_p (glibtop *server) +_glibtop_init_proc_map_s (glibtop *server) { server->sysdeps.proc_map = _glibtop_sysdeps_proc_map; } @@ -185,7 +184,7 @@ parse_line(char* line, glibtop_map_entry * -glibtop_get_proc_map_p (glibtop *server, glibtop_proc_map *buf, pid_t pid) +glibtop_get_proc_map_s (glibtop *server, glibtop_proc_map *buf, pid_t pid) { char procfilename[GLIBTOP_MAP_FILENAME_LEN+1]; @@ -215,17 +214,10 @@ glibtop_get_proc_map_p (glibtop *server, glibtop_proc_map *buf, pid_t pid) snprintf (procfilename, sizeof procfilename, filename, (unsigned)pid); - glibtop_suid_enter (server); - if((maps = fopen (procfilename, "r")) == NULL) { - glibtop_suid_leave (server); return (glibtop_map_entry*) g_array_free(entry_list, TRUE); } - glibtop_debug("opened %p", maps); - - glibtop_suid_leave (server); - while(TRUE) { unsigned long perm; diff --git a/sysdeps/linux/procmap.c.suid_example b/sysdeps/linux/procmap.c.suid_example new file mode 100644 index 00000000..07a7a680 --- /dev/null +++ b/sysdeps/linux/procmap.c.suid_example @@ -0,0 +1,334 @@ +/* +Don't forget to set + #define GLIBTOP_SUID_PROC_MAP (1 << GLIBTOP_SYSDEPS_PROC_MAP) +in sysdeps/linux/glibtop_server.h + +Make sure to pair each glibtop_suid_enter with a glibtop_suid_leave. +*/ + +/* Copyright (C) 1998-99 Martin Baulig + This file is part of LibGTop 1.0. + + Contributed by Martin Baulig <martin@home-of-linux.org>, April 1998. + + LibGTop is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + LibGTop is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with LibGTop; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include <config.h> +#include <glib.h> + +#include <glibtop.h> +#include <glibtop/error.h> +#include <glibtop/procmap.h> + +#include <linux/kdev_t.h> +#include <stddef.h> + +#include "glibtop_private.h" +#include "glibtop_suid.h" + +#include "procmap_smaps.c" + +#define MAPS_FILE "/proc/%u/maps" +#define SMAPS_FILE "/proc/%u/smaps" + + +#define PROC_MAPS_FORMAT "%16" G_GINT64_MODIFIER "x-%16" G_GINT64_MODIFIER "x %4c %16" G_GINT64_MODIFIER "x %02hx:%02hx %" G_GINT64_MODIFIER "u%*[ ]%n" + + +static const unsigned long _glibtop_sysdeps_proc_map = +(1L << GLIBTOP_PROC_MAP_NUMBER) + (1L << GLIBTOP_PROC_MAP_TOTAL) + +(1L << GLIBTOP_PROC_MAP_SIZE); + +static const unsigned long _glibtop_sysdeps_map_entry = +(1L << GLIBTOP_MAP_ENTRY_START) + (1L << GLIBTOP_MAP_ENTRY_END) + +(1L << GLIBTOP_MAP_ENTRY_OFFSET) + (1L << GLIBTOP_MAP_ENTRY_PERM) + +(1L << GLIBTOP_MAP_ENTRY_INODE) + (1L << GLIBTOP_MAP_ENTRY_DEVICE) + +(1L << GLIBTOP_MAP_ENTRY_FILENAME); + +static const unsigned long _glibtop_sysdeps_map_entry_smaps = +(1UL << GLIBTOP_MAP_ENTRY_SIZE) + (1UL << GLIBTOP_MAP_ENTRY_RSS) + +(1UL << GLIBTOP_MAP_ENTRY_PSS) + (1UL << GLIBTOP_MAP_ENTRY_SWAP) + +(1UL << GLIBTOP_MAP_ENTRY_SHARED_DIRTY) + (1UL << GLIBTOP_MAP_ENTRY_SHARED_CLEAN) + +(1UL << GLIBTOP_MAP_ENTRY_PRIVATE_DIRTY) + (1UL << GLIBTOP_MAP_ENTRY_PRIVATE_CLEAN); + + +/* Init function. */ + +void +_glibtop_init_proc_map_p (glibtop *server) +{ + server->sysdeps.proc_map = _glibtop_sysdeps_proc_map; +} + +/* Provides detailed information about a process. */ + + +static const char* +is_smap_value(const char* s) +{ + for ( ; *s; ++s) { + + if (isspace(*s)) + return NULL; + + if (*s == ':') + return s; + } + + return NULL; +} + + +/* + Returns whether line is a 'value' line + and add if we know its meaning +*/ +static gboolean +parse_smaps(glibtop_map_entry *entry, const char* line) +{ + + const struct smap_value* smap; + size_t len; + const char* colon; + + if ((colon = is_smap_value(line)) == NULL) + return FALSE; + + len = colon - line; + smap = _glibtop_find_smap(line, len); + +// g_debug("smap %s -> %p", line, smap); + + if (smap) { + char *offset; + guint64 *value; + + offset = (void*) entry; + offset += smap->offset; + value = (void*) offset; + + *value = get_scaled(line + len, NULL); + } + + return TRUE; +} + + +/* + sscanf is too slow + and system-monitor calls procmap for each pid every second + + manual parsing is faster + + error checking is weaker +*/ + +static gboolean +parse_line(char* line, + guint64* start, guint64* end, char flags[4], guint64* offset, + gushort* dev_major, gushort* dev_minor, guint64* inode, + char** filename) +{ + /* %16llx-%16llx %4c %16llx %02hx:%02hx %llu%*[ ]%n */ + + char *p, *next; + + p = line; + + *start = strtoull(p, &p, 16); + + if (G_UNLIKELY(*p != '-')) + return FALSE; + p++; + + *end = strtoull(p, &p, 16); + + p = next_token(p); + + memcpy(flags, p, 4); + p += 4; + + *offset = strtoull(p, &p, 16); + + *dev_major = strtoul(p, &p, 16); + + if (G_UNLIKELY(*p != ':')) + return FALSE; + p++; + + *dev_minor = strtoul(p, &p, 16); + + *inode = strtoull(p, &p, 10); + + p = next_token(p); + + *filename = p; + + for ( ; *p; p++) { + if (*p == '\n') { + *p = '\0'; + break; + } + } + + return TRUE; +} + + + + + +glibtop_map_entry * +glibtop_get_proc_map_p (glibtop *server, glibtop_proc_map *buf, pid_t pid) +{ + char procfilename[GLIBTOP_MAP_FILENAME_LEN+1]; + + /* + default size of 100 maybe inaccurate. + It's the average number of entry per process on my laptop + */ + + size_t added = 0, entry_list_capacity = 100; + GArray *entry_list = g_array_sized_new(FALSE, FALSE, + sizeof(glibtop_map_entry), + entry_list_capacity); + FILE *maps; + const char *filename; + gboolean has_smaps; + char *line = NULL; + size_t line_size = 0; + + memset (buf, 0, sizeof (glibtop_proc_map)); + + has_smaps = server->os_version_code >= LINUX_VERSION_CODE(2, 6, 14); + + if (has_smaps) + filename = SMAPS_FILE; + else + filename = MAPS_FILE; + + snprintf (procfilename, sizeof procfilename, filename, (unsigned)pid); + + glibtop_suid_enter (server); + + if((maps = fopen (procfilename, "r")) == NULL) { + glibtop_suid_leave (server); + return (glibtop_map_entry*) g_array_free(entry_list, TRUE); + } + + glibtop_debug("opened %p", maps); + + glibtop_suid_leave (server); + + while(TRUE) + { + unsigned long perm; + /* int line_end; */ + + unsigned short dev_major, dev_minor; + guint64 start, end, offset, inode; + char flags[4]; + char *filename; + + glibtop_map_entry *entry; + + if (getline(&line, &line_size, maps) == -1) + break; + + new_entry_line: + + if (!parse_line(line, + &start, &end, flags, &offset, + &dev_major, &dev_minor, &inode, &filename)) + continue; + + /* + if (sscanf(line, PROC_MAPS_FORMAT, + &start, &end, flags, &offset, + &dev_major, &dev_minor, &inode, &line_end) != 7) + continue; + + filename = line + line_end; + g_strstrip(filename); + */ + + /* Compute access permissions. */ + perm = 0; + + if (flags [0] == 'r') + perm |= GLIBTOP_MAP_PERM_READ; + + if (flags [1] == 'w') + perm |= GLIBTOP_MAP_PERM_WRITE; + + if (flags [2] == 'x') + perm |= GLIBTOP_MAP_PERM_EXECUTE; + + if (flags [3] == 's') + perm |= GLIBTOP_MAP_PERM_SHARED; + else if (flags [3] == 'p') + perm |= GLIBTOP_MAP_PERM_PRIVATE; + + /* + avoid copying the entry, grow by 1 and point to the last + element. + */ + + if (G_UNLIKELY(added >= entry_list_capacity)) { + entry_list_capacity *= 2; + g_array_set_size(entry_list, entry_list_capacity); + } + + entry = &g_array_index(entry_list, glibtop_map_entry, added++); + + entry->flags = _glibtop_sysdeps_map_entry; + entry->start = start; + entry->end = end; + entry->offset = offset; + entry->perm = perm; + entry->device = MKDEV(dev_major, dev_minor); + entry->inode = inode; + g_strlcpy(entry->filename, filename, sizeof entry->filename); + + if (has_smaps) { + ssize_t ret; + entry->flags |= _glibtop_sysdeps_map_entry_smaps; + + while ((ret = getline(&line, &line_size, maps)) != -1) { + if (!parse_smaps(entry, line)) + goto new_entry_line; + } + + if (ret == -1) + goto eof; + } + } + +eof: + + g_array_set_size(entry_list, added); + free(line); + fclose (maps); + + buf->flags = _glibtop_sysdeps_proc_map; + + buf->number = added; + buf->size = sizeof (glibtop_map_entry); + buf->total = buf->number * buf->size; + + return (glibtop_map_entry*) g_array_free(entry_list, FALSE); +} |