Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cmd] Allow for filtering about maps permissions in vmmap #1111

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/commands/vmmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ place). For example, you can learn that ELF running on SPARC architectures alway
and `heap` sections set as Read/Write/Execute.

`vmmap` can accept multiple arguments, either patterns to match again mapping names, or addresses
to determine which section it belongs to:
to determine which section it belongs to, or the permissions of the sections to match:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some examples of --perms would be nice too


1. `-a` / `--addr`:
- filter by address -> parses the next argument as an integer or asks gdb to interpret the value
Expand Down
48 changes: 43 additions & 5 deletions gef.py
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,30 @@ def from_info_mem(cls, perm_str: str) -> "Permission":
if "x" in perm_str: perm |= Permission.EXECUTE
return perm

@classmethod
def from_filter_repr(cls, filter_str: str) -> List["Permission"]:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be worth adding unit test for this function alone.

perms = [cls(0)]
if filter_str[0] == "r":
ValekoZ marked this conversation as resolved.
Show resolved Hide resolved
for i in range(len(perms)):
perms[i] |= Permission.READ
elif filter_str[0] == "?":
for i in range(len(perms)):
perms.append(perms[i] | Permission.READ)
if filter_str[1] == "w":
for i in range(len(perms)):
perms[i] |= Permission.WRITE
elif filter_str[1] == "?":
for i in range(len(perms)):
perms.append(perms[i] | Permission.WRITE)
if filter_str[2] == "x":
for i in range(len(perms)):
perms[i] |= Permission.EXECUTE
elif filter_str[2] == "?":
for i in range(len(perms)):
perms.append(perms[i] | Permission.EXECUTE)
return perms



class Section:
"""GEF representation of process memory sections."""
Expand Down Expand Up @@ -8895,7 +8919,9 @@ class VMMapCommand(GenericCommand):
_example_ = f"{_cmdline_} libc"

@only_if_gdb_running
@parse_arguments({"unknown_types": [""]}, {("--addr", "-a"): [""], ("--name", "-n"): [""]})
@parse_arguments({"unknown_types": [""]}, {("--addr", "-a"): [""],
("--name", "-n"): [""],
("--perms", "-p"): [""]})
def do_invoke(self, _: List[str], **kwargs: Any) -> None:
args : argparse.Namespace = kwargs["arguments"]
vmmap = gef.memory.maps
Expand All @@ -8905,6 +8931,10 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None:

addrs: Dict[str, int] = {x: parse_address(x) for x in args.addr}
names: List[str] = [x for x in args.name]
perms: Set[Permission] = set()

for x in args.perms:
perms = perms.union(Permission.from_filter_repr(x))

for arg in args.unknown_types:
if not arg:
Expand All @@ -8916,12 +8946,19 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None:
addr = safe_parse_and_eval(arg)

if addr is None:
if arg[0] in 'r-?' and \
arg[1] in 'w-?' and \
arg[2] in 'x-?':
perms = perms.union(Permission.from_filter_repr(arg))
warn(f"`{arg}` has no type specified. We guessed it was a perm filter.")
continue

names.append(arg)
warn(f"`{arg}` has no type specified. We guessed it was a name filter.")
else:
addrs[arg] = int(addr)
warn(f"`{arg}` has no type specified. We guessed it was an address filter.")
warn("You can use --name or --addr before the filter value for specifying its type manually.")
warn("You can use --name, --addr or --perms before the filter value for specifying its type manually.")
gef_print()

if not gef.config["gef.disable_color"]:
Expand All @@ -8938,12 +8975,13 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None:
names_filter = [f"name = '{x}'" for x in names if x in entry.path]
addrs_filter = [f"addr = {self.format_addr_filter(arg, addr)}" for arg, addr in addrs.items()
if entry.page_start <= addr < entry.page_end]
filter_content = f"[{' & '.join([*names_filter, *addrs_filter])}]"
perms_filter = [f"perms = {x}" for x in perms if entry.permission == x]
filter_content = f"[{' & '.join([*names_filter, *addrs_filter, *perms_filter])}]"

if not names and not addrs:
if not names and not addrs and not perms:
self.print_entry(entry)

elif names_filter or addrs_filter:
elif names_filter or addrs_filter or perms_filter:
if filter_content != last_printed_filter:
gef_print() # skip a line between different filters
gef_print(Color.greenify(filter_content))
Expand Down
20 changes: 20 additions & 0 deletions tests/commands/vmmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ def test_cmd_vmmap(self):
assert "`$pc` has no type specified. We guessed it was an address filter." in res
self.assertEqual(len(res.splitlines()), 8)

res = gdb.execute("vmmap r-?", to_string=True)
assert "`r-?` has no type specified. We guessed it was a perm filter." in res
self.assertGreater(len(res.splitlines()), 3)

def test_cmd_vmmap_addr(self):
gef, gdb = self._gef, self._gdb
gdb.execute("start")
Expand All @@ -48,3 +52,19 @@ def test_cmd_vmmap_name(self):

res = gdb.execute("vmmap --name stack", to_string=True)
self.assertEqual(len(res.splitlines()), 5)

def test_cmd_vmmap_perm(self):
gdb = self._gdb
gdb.execute("start")

res = gdb.execute("vmmap -p r?-", to_string=True)
self.assertGreater(len(res.splitlines()), 5)

res = gdb.execute("vmmap --perms r?-", to_string=True)
self.assertGreater(len(res.splitlines()), 5)
Comment on lines +60 to +64
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can go further in checking the output, this doesn't really check the output is as intended. Also those tests being equivalent, you can thoroughly check the strings in the 1st assert, then check that the 1st result equals the 2nd.

Suggested change
res = gdb.execute("vmmap -p r?-", to_string=True)
self.assertGreater(len(res.splitlines()), 5)
res = gdb.execute("vmmap --perms r?-", to_string=True)
self.assertGreater(len(res.splitlines()), 5)
res1 = gdb.execute("vmmap -p r?-", to_string=True)
lines1 = res.splitlines()
self.assertGreater(len(lines), 5)
for line in lines1:
perm_str = line.split()[3]
assert perm_str[0] == 'r'
assert perm_str[1] in ('w', '-')
assert perm_str[2] == '-'
res2 = gdb.execute("vmmap --perms r?-", to_string=True)
assert res1 == res2


res = gdb.execute("vmmap -p rw-", to_string=True)
self.assertGreater(len(res.splitlines()), 5)

res = gdb.execute("vmmap --perms rw-", to_string=True)
self.assertGreater(len(res.splitlines()), 5)
Loading