Skip to content

Commit e6a06c5

Browse files
authored
Merge pull request #48 from P403n1x87/fix/where-pipe-permissions
fix: where mode named pipe permissions
2 parents 27b4023 + 08fcad9 commit e6a06c5

File tree

5 files changed

+46
-17
lines changed

5 files changed

+46
-17
lines changed

echion/__main__.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,24 @@ def detach(pid: int) -> None:
3131
def attach(args: argparse.Namespace) -> None:
3232
from hypno import inject_py
3333

34-
script = dedent(
35-
f"""
36-
from echion.bootstrap.attach import attach
37-
attach({args.__dict__!r})
38-
"""
39-
).strip()
40-
4134
pid = args.pid or args.where
4235

4336
try:
37+
pipe_name = None
4438
if args.where:
4539
pipe_name = Path(tempfile.gettempdir()) / f"echion-{pid}"
4640
os.mkfifo(pipe_name)
41+
# This named pipe is likely created by the superuser, so we need to
42+
# make it writable by everyone to allow the target process to write
43+
# to it.
44+
os.chmod(pipe_name, 0o666)
45+
46+
script = dedent(
47+
f"""
48+
from echion.bootstrap.attach import attach
49+
attach({args.__dict__!r}, {repr(str(pipe_name)) if pipe_name is not None else str(None)})
50+
"""
51+
).strip()
4752

4853
inject_py(pid, script)
4954

@@ -53,6 +58,7 @@ def attach(args: argparse.Namespace) -> None:
5358
from time import monotonic as time
5459

5560
end = time() + args.exposure
61+
5662
while not args.where:
5763
try:
5864
os.kill(pid, 0)
@@ -61,11 +67,12 @@ def attach(args: argparse.Namespace) -> None:
6167
if end is not None and time() > end:
6268
break
6369
os.sched_yield()
70+
6471
except (KeyboardInterrupt, ProcessLookupError):
6572
pass
6673

6774
# Read the output
68-
if args.where and pipe_name.exists():
75+
if args.where and pipe_name is not None and pipe_name.exists():
6976
with pipe_name.open("r") as f:
7077
while True:
7178
line = f.readline()
@@ -76,7 +83,7 @@ def attach(args: argparse.Namespace) -> None:
7683
detach(pid)
7784

7885
finally:
79-
if args.where and pipe_name.exists():
86+
if args.where and pipe_name is not None and pipe_name.exists():
8087
pipe_name.unlink()
8188

8289

echion/bootstrap/attach.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import typing as t
77

88

9-
def attach(config: t.Dict[str, str]) -> None:
9+
def attach(config: t.Dict[str, str], pipe_name: t.Optional[str] = None) -> None:
1010
os.environ["ECHION_CPU"] = str(int(config["cpu"]))
1111
os.environ["ECHION_NATIVE"] = str(int(config["native"]))
1212
os.environ["ECHION_OUTPUT"] = config["output"]
@@ -15,6 +15,12 @@ def attach(config: t.Dict[str, str]) -> None:
1515

1616
from echion.bootstrap import start
1717

18+
# This is used in where mode for IPC.
19+
if pipe_name is not None:
20+
from echion.core import set_pipe_name
21+
22+
set_pipe_name(pipe_name)
23+
1824
start()
1925

2026

echion/config.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ static int native = 0;
2626
// Where mode
2727
static int where = 0;
2828

29+
// Pipe name (where mode IPC)
30+
static std::string pipe_name;
31+
2932
// ----------------------------------------------------------------------------
3033
static PyObject *
3134
set_interval(PyObject *Py_UNUSED(m), PyObject *args)
@@ -77,3 +80,16 @@ set_where(PyObject *Py_UNUSED(m), PyObject *args)
7780

7881
Py_RETURN_NONE;
7982
}
83+
84+
// ----------------------------------------------------------------------------
85+
static PyObject *
86+
set_pipe_name(PyObject *Py_UNUSED(m), PyObject *args)
87+
{
88+
const char *name;
89+
if (!PyArg_ParseTuple(args, "s", &name))
90+
return NULL;
91+
92+
pipe_name = name;
93+
94+
Py_RETURN_NONE;
95+
}

echion/core.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ def set_interval(interval: int) -> None: ...
2323
def set_cpu(cpu: bool) -> None: ...
2424
def set_native(native: bool) -> None: ...
2525
def set_where(where: bool) -> None: ...
26+
def set_pipe_name(name: str) -> None: ...

echion/coremodule.cc

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,13 @@ _sampler()
138138

139139
if (where)
140140
{
141-
auto pipe_name = std::filesystem::temp_directory_path() / ("echion-" + std::to_string(getpid()));
142141
std::ofstream pipe(pipe_name, std::ios::out);
143-
if (!pipe)
144-
{
145-
std::cerr << "Failed to open pipe " << pipe_name << std::endl;
146-
return;
147-
}
148142

149-
do_where(pipe);
143+
if (pipe)
144+
do_where(pipe);
145+
146+
else
147+
std::cerr << "Failed to open pipe " << pipe_name << std::endl;
150148

151149
running = 0;
152150

@@ -398,6 +396,7 @@ static PyMethodDef echion_core_methods[] = {
398396
{"set_cpu", set_cpu, METH_VARARGS, "Set whether to use CPU time instead of wall time"},
399397
{"set_native", set_native, METH_VARARGS, "Set whether to sample the native stacks"},
400398
{"set_where", set_where, METH_VARARGS, "Set whether to use where mode"},
399+
{"set_pipe_name", set_pipe_name, METH_VARARGS, "Set the pipe name"},
401400
{NULL, NULL, 0, NULL} /* Sentinel */
402401
};
403402

0 commit comments

Comments
 (0)