On Thu, Apr 20, 2017 at 12:08:02PM +0200, Sebastien Marie wrote:
>
> profil(2) syscall itself could be allowed in "stdio" with specifics
> arguments: profil(NULL, 0, 0, 0) (but some code inspection should be
> done before: extending "stdio" is not neutral - think to programs like
> ssh or tcpdump that relies on "stdio" for sandboxing). Only this
> particular call of profil(2) is ran under pledge(2): the first call is
> done before calling main() so before any pledge(2) call setted by
> user code.
>
here a diff for allowing partially profil(2) under "stdio". It only
permits to stop the profiling (else it is a pledge violation).
the code path in kernel that is exposed is:
- stopprofclock()
- clear PS_PROFIL bit
- setstatclockrate()
- mc146818_write()
I am unfamiliar with this code path. Maybe it would be unacceptable for
a pledged program to reach it.
please note, that with the diff, a pledged and profiled program still
needs "wpath cpath" promises for creating the gmon.out file. Else it
will be aborted by pledge.
but it ameliorates the profil(2) support we have in pledged context (not
possible at all for now).
--
Sebastien Marie
Index: sys/kern/kern_pledge.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_pledge.c,v
retrieving revision 1.204
diff -u -p -r1.204 kern_pledge.c
--- sys/kern/kern_pledge.c 17 Apr 2017 20:22:14 -0000 1.204
+++ sys/kern/kern_pledge.c 20 Apr 2017 14:19:31 -0000
@@ -143,6 +143,9 @@ const uint64_t pledge_syscalls[SYS_MAXSY
*/
[SYS_sysctl] = PLEDGE_STDIO,
+ /* only stop profiling */
+ [SYS_profil] = PLEDGE_STDIO,
+
/* Support for malloc(3) family of operations */
[SYS_getentropy] = PLEDGE_STDIO,
[SYS_madvise] = PLEDGE_STDIO,
@@ -1552,6 +1555,19 @@ pledge_kill(struct proc *p, pid_t pid)
if (pid == 0 || pid == p->p_p->ps_pid)
return 0;
return pledge_fail(p, EPERM, PLEDGE_PROC);
+}
+
+int
+pledge_profil(struct proc *p, u_int scale)
+{
+ if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
+ return 0;
+
+ /* stop profiling */
+ if ((p->p_p->ps_flags & PS_PROFIL) && (scale == 0))
+ return 0;
+
+ return pledge_fail(p, EINVAL, 0);
}
int
Index: sys/kern/subr_prof.c
===================================================================
RCS file: /cvs/src/sys/kern/subr_prof.c,v
retrieving revision 1.30
diff -u -p -r1.30 subr_prof.c
--- sys/kern/subr_prof.c 4 Sep 2016 09:22:29 -0000 1.30
+++ sys/kern/subr_prof.c 20 Apr 2017 14:19:31 -0000
@@ -39,6 +39,7 @@
#include <sys/mount.h>
#include <sys/sysctl.h>
#include <sys/syscallargs.h>
+#include <sys/pledge.h>
#if defined(GPROF) || defined(DDBPROF)
@@ -235,10 +236,14 @@ sys_profil(struct proc *p, void *v, regi
struct process *pr = p->p_p;
struct uprof *upp;
int s;
+ u_int scale = SCARG(uap, scale);
+ int error;
- if (SCARG(uap, scale) > (1 << 16))
+ if (scale > (1 << 16))
return (EINVAL);
- if (SCARG(uap, scale) == 0) {
+ if ((error = pledge_profil(p, scale)))
+ return (error);
+ if (scale == 0) {
stopprofclock(pr);
return (0);
}
@@ -247,7 +252,7 @@ sys_profil(struct proc *p, void *v, regi
/* Block profile interrupts while changing state. */
s = splstatclock();
upp->pr_off = SCARG(uap, offset);
- upp->pr_scale = SCARG(uap, scale);
+ upp->pr_scale = scale;
upp->pr_base = (caddr_t)SCARG(uap, samples);
upp->pr_size = SCARG(uap, size);
startprofclock(pr);
Index: sys/sys/pledge.h
===================================================================
RCS file: /cvs/src/sys/sys/pledge.h,v
retrieving revision 1.30
diff -u -p -r1.30 pledge.h
--- sys/sys/pledge.h 23 Jan 2017 04:25:05 -0000 1.30
+++ sys/sys/pledge.h 20 Apr 2017 14:19:31 -0000
@@ -133,6 +133,7 @@ int pledge_flock(struct proc *p);
int pledge_fcntl(struct proc *p, int cmd);
int pledge_swapctl(struct proc *p);
int pledge_kill(struct proc *p, pid_t pid);
+int pledge_profil(struct proc *p, u_int scale);
int pledge_protexec(struct proc *p, int prot);
#define PLEDGE_MAXPATHS 8192