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

Reply via email to