LCOV - code coverage report
Current view: top level - drivers/connector - cn_proc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 97 162 59.9 %
Date: 2014-02-18 Functions: 10 11 90.9 %
Branches: 22 37 59.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * cn_proc.c - process events connector
       3                 :            :  *
       4                 :            :  * Copyright (C) Matt Helsley, IBM Corp. 2005
       5                 :            :  * Based on cn_fork.c by Guillaume Thouvenin <guillaume.thouvenin@bull.net>
       6                 :            :  * Original copyright notice follows:
       7                 :            :  * Copyright (C) 2005 BULL SA.
       8                 :            :  *
       9                 :            :  *
      10                 :            :  * This program is free software; you can redistribute it and/or modify
      11                 :            :  * it under the terms of the GNU General Public License as published by
      12                 :            :  * the Free Software Foundation; either version 2 of the License, or
      13                 :            :  * (at your option) any later version.
      14                 :            :  *
      15                 :            :  * This program is distributed in the hope that it will be useful,
      16                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      17                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18                 :            :  * GNU General Public License for more details.
      19                 :            :  *
      20                 :            :  * You should have received a copy of the GNU General Public License
      21                 :            :  * along with this program; if not, write to the Free Software
      22                 :            :  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
      23                 :            :  */
      24                 :            : 
      25                 :            : #include <linux/module.h>
      26                 :            : #include <linux/kernel.h>
      27                 :            : #include <linux/ktime.h>
      28                 :            : #include <linux/init.h>
      29                 :            : #include <linux/connector.h>
      30                 :            : #include <linux/gfp.h>
      31                 :            : #include <linux/ptrace.h>
      32                 :            : #include <linux/atomic.h>
      33                 :            : #include <linux/pid_namespace.h>
      34                 :            : 
      35                 :            : #include <linux/cn_proc.h>
      36                 :            : 
      37                 :            : /*
      38                 :            :  * Size of a cn_msg followed by a proc_event structure.  Since the
      39                 :            :  * sizeof struct cn_msg is a multiple of 4 bytes, but not 8 bytes, we
      40                 :            :  * add one 4-byte word to the size here, and then start the actual
      41                 :            :  * cn_msg structure 4 bytes into the stack buffer.  The result is that
      42                 :            :  * the immediately following proc_event structure is aligned to 8 bytes.
      43                 :            :  */
      44                 :            : #define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event) + 4)
      45                 :            : 
      46                 :            : /* See comment above; we test our assumption about sizeof struct cn_msg here. */
      47                 :            : static inline struct cn_msg *buffer_to_cn_msg(__u8 *buffer)
      48                 :            : {
      49                 :            :         BUILD_BUG_ON(sizeof(struct cn_msg) != 20);
      50                 :            :         return (struct cn_msg *)(buffer + 4);
      51                 :            : }
      52                 :            : 
      53                 :            : static atomic_t proc_event_num_listeners = ATOMIC_INIT(0);
      54                 :            : static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC };
      55                 :            : 
      56                 :            : /* proc_event_counts is used as the sequence number of the netlink message */
      57                 :            : static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 };
      58                 :            : 
      59                 :            : static inline void get_seq(__u32 *ts, int *cpu)
      60                 :            : {
      61                 :         42 :         preempt_disable();
      62                 :        126 :         *ts = __this_cpu_inc_return(proc_event_counts) - 1;
      63                 :         42 :         *cpu = smp_processor_id();
      64                 :         42 :         preempt_enable();
      65                 :            : }
      66                 :            : 
      67                 :          0 : void proc_fork_connector(struct task_struct *task)
      68                 :            : {
      69                 :            :         struct cn_msg *msg;
      70                 :            :         struct proc_event *ev;
      71                 :            :         __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
      72                 :            :         struct timespec ts;
      73                 :            :         struct task_struct *parent;
      74                 :            : 
      75         [ +  + ]:    1151924 :         if (atomic_read(&proc_event_num_listeners) < 1)
      76                 :    1151912 :                 return;
      77                 :            : 
      78                 :            :         msg = buffer_to_cn_msg(buffer);
      79                 :            :         ev = (struct proc_event *)msg->data;
      80                 :         12 :         memset(&ev->event_data, 0, sizeof(ev->event_data));
      81                 :            :         get_seq(&msg->seq, &ev->cpu);
      82                 :         12 :         ktime_get_ts(&ts); /* get high res monotonic timestamp */
      83                 :         12 :         ev->timestamp_ns = timespec_to_ns(&ts);
      84                 :         12 :         ev->what = PROC_EVENT_FORK;
      85                 :            :         rcu_read_lock();
      86                 :         12 :         parent = rcu_dereference(task->real_parent);
      87                 :         12 :         ev->event_data.fork.parent_pid = parent->pid;
      88                 :         12 :         ev->event_data.fork.parent_tgid = parent->tgid;
      89                 :            :         rcu_read_unlock();
      90                 :         12 :         ev->event_data.fork.child_pid = task->pid;
      91                 :         12 :         ev->event_data.fork.child_tgid = task->tgid;
      92                 :            : 
      93                 :         12 :         memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
      94                 :         12 :         msg->ack = 0; /* not used */
      95                 :         12 :         msg->len = sizeof(*ev);
      96                 :         12 :         msg->flags = 0; /* not used */
      97                 :            :         /*  If cn_netlink_send() failed, the data is not sent */
      98                 :         12 :         cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
      99                 :            : }
     100                 :            : 
     101                 :          0 : void proc_exec_connector(struct task_struct *task)
     102                 :            : {
     103                 :            :         struct cn_msg *msg;
     104                 :            :         struct proc_event *ev;
     105                 :            :         struct timespec ts;
     106                 :            :         __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
     107                 :            : 
     108         [ +  + ]:      58976 :         if (atomic_read(&proc_event_num_listeners) < 1)
     109                 :      58965 :                 return;
     110                 :            : 
     111                 :            :         msg = buffer_to_cn_msg(buffer);
     112                 :            :         ev = (struct proc_event *)msg->data;
     113                 :         11 :         memset(&ev->event_data, 0, sizeof(ev->event_data));
     114                 :            :         get_seq(&msg->seq, &ev->cpu);
     115                 :         11 :         ktime_get_ts(&ts); /* get high res monotonic timestamp */
     116                 :         11 :         ev->timestamp_ns = timespec_to_ns(&ts);
     117                 :         11 :         ev->what = PROC_EVENT_EXEC;
     118                 :         11 :         ev->event_data.exec.process_pid = task->pid;
     119                 :         11 :         ev->event_data.exec.process_tgid = task->tgid;
     120                 :            : 
     121                 :         11 :         memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
     122                 :         11 :         msg->ack = 0; /* not used */
     123                 :         11 :         msg->len = sizeof(*ev);
     124                 :         11 :         msg->flags = 0; /* not used */
     125                 :         11 :         cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
     126                 :            : }
     127                 :            : 
     128                 :          0 : void proc_id_connector(struct task_struct *task, int which_id)
     129                 :            : {
     130                 :            :         struct cn_msg *msg;
     131                 :            :         struct proc_event *ev;
     132                 :            :         __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
     133                 :            :         struct timespec ts;
     134                 :            :         const struct cred *cred;
     135                 :            : 
     136         [ +  + ]:       5162 :         if (atomic_read(&proc_event_num_listeners) < 1)
     137                 :       5160 :                 return;
     138                 :            : 
     139                 :            :         msg = buffer_to_cn_msg(buffer);
     140                 :            :         ev = (struct proc_event *)msg->data;
     141                 :          2 :         memset(&ev->event_data, 0, sizeof(ev->event_data));
     142                 :          2 :         ev->what = which_id;
     143                 :          2 :         ev->event_data.id.process_pid = task->pid;
     144                 :          2 :         ev->event_data.id.process_tgid = task->tgid;
     145                 :            :         rcu_read_lock();
     146                 :       5164 :         cred = __task_cred(task);
     147         [ +  + ]:       5164 :         if (which_id == PROC_EVENT_UID) {
     148                 :          2 :                 ev->event_data.id.r.ruid = from_kuid_munged(&init_user_ns, cred->uid);
     149                 :          1 :                 ev->event_data.id.e.euid = from_kuid_munged(&init_user_ns, cred->euid);
     150         [ +  - ]:       5163 :         } else if (which_id == PROC_EVENT_GID) {
     151                 :          2 :                 ev->event_data.id.r.rgid = from_kgid_munged(&init_user_ns, cred->gid);
     152                 :          1 :                 ev->event_data.id.e.egid = from_kgid_munged(&init_user_ns, cred->egid);
     153                 :            :         } else {
     154                 :            :                 rcu_read_unlock();
     155                 :            :                 return;
     156                 :            :         }
     157                 :            :         rcu_read_unlock();
     158                 :            :         get_seq(&msg->seq, &ev->cpu);
     159                 :          2 :         ktime_get_ts(&ts); /* get high res monotonic timestamp */
     160                 :          2 :         ev->timestamp_ns = timespec_to_ns(&ts);
     161                 :            : 
     162                 :          2 :         memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
     163                 :          2 :         msg->ack = 0; /* not used */
     164                 :          2 :         msg->len = sizeof(*ev);
     165                 :          2 :         msg->flags = 0; /* not used */
     166                 :          2 :         cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
     167                 :            : }
     168                 :            : 
     169                 :          0 : void proc_sid_connector(struct task_struct *task)
     170                 :            : {
     171                 :            :         struct cn_msg *msg;
     172                 :            :         struct proc_event *ev;
     173                 :            :         struct timespec ts;
     174                 :            :         __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
     175                 :            : 
     176         [ -  + ]:        117 :         if (atomic_read(&proc_event_num_listeners) < 1)
     177                 :        117 :                 return;
     178                 :            : 
     179                 :            :         msg = buffer_to_cn_msg(buffer);
     180                 :            :         ev = (struct proc_event *)msg->data;
     181                 :          0 :         memset(&ev->event_data, 0, sizeof(ev->event_data));
     182                 :            :         get_seq(&msg->seq, &ev->cpu);
     183                 :          0 :         ktime_get_ts(&ts); /* get high res monotonic timestamp */
     184                 :          0 :         ev->timestamp_ns = timespec_to_ns(&ts);
     185                 :          0 :         ev->what = PROC_EVENT_SID;
     186                 :          0 :         ev->event_data.sid.process_pid = task->pid;
     187                 :          0 :         ev->event_data.sid.process_tgid = task->tgid;
     188                 :            : 
     189                 :          0 :         memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
     190                 :          0 :         msg->ack = 0; /* not used */
     191                 :          0 :         msg->len = sizeof(*ev);
     192                 :          0 :         msg->flags = 0; /* not used */
     193                 :          0 :         cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
     194                 :            : }
     195                 :            : 
     196                 :          0 : void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
     197                 :            : {
     198                 :            :         struct cn_msg *msg;
     199                 :            :         struct proc_event *ev;
     200                 :            :         struct timespec ts;
     201                 :            :         __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
     202                 :            : 
     203         [ -  + ]:         64 :         if (atomic_read(&proc_event_num_listeners) < 1)
     204                 :         64 :                 return;
     205                 :            : 
     206                 :            :         msg = buffer_to_cn_msg(buffer);
     207                 :            :         ev = (struct proc_event *)msg->data;
     208                 :          0 :         memset(&ev->event_data, 0, sizeof(ev->event_data));
     209                 :            :         get_seq(&msg->seq, &ev->cpu);
     210                 :          0 :         ktime_get_ts(&ts); /* get high res monotonic timestamp */
     211                 :          0 :         ev->timestamp_ns = timespec_to_ns(&ts);
     212                 :          0 :         ev->what = PROC_EVENT_PTRACE;
     213                 :          0 :         ev->event_data.ptrace.process_pid  = task->pid;
     214                 :          0 :         ev->event_data.ptrace.process_tgid = task->tgid;
     215         [ #  # ]:         64 :         if (ptrace_id == PTRACE_ATTACH) {
     216                 :          0 :                 ev->event_data.ptrace.tracer_pid  = current->pid;
     217                 :          0 :                 ev->event_data.ptrace.tracer_tgid = current->tgid;
     218         [ #  # ]:          0 :         } else if (ptrace_id == PTRACE_DETACH) {
     219                 :          0 :                 ev->event_data.ptrace.tracer_pid  = 0;
     220                 :          0 :                 ev->event_data.ptrace.tracer_tgid = 0;
     221                 :            :         } else
     222                 :            :                 return;
     223                 :            : 
     224                 :          0 :         memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
     225                 :          0 :         msg->ack = 0; /* not used */
     226                 :          0 :         msg->len = sizeof(*ev);
     227                 :          0 :         msg->flags = 0; /* not used */
     228                 :          0 :         cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
     229                 :            : }
     230                 :            : 
     231                 :          0 : void proc_comm_connector(struct task_struct *task)
     232                 :            : {
     233                 :            :         struct cn_msg *msg;
     234                 :            :         struct proc_event *ev;
     235                 :            :         struct timespec ts;
     236                 :            :         __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
     237                 :            : 
     238         [ -  + ]:         31 :         if (atomic_read(&proc_event_num_listeners) < 1)
     239                 :         31 :                 return;
     240                 :            : 
     241                 :            :         msg = buffer_to_cn_msg(buffer);
     242                 :            :         ev = (struct proc_event *)msg->data;
     243                 :          0 :         memset(&ev->event_data, 0, sizeof(ev->event_data));
     244                 :            :         get_seq(&msg->seq, &ev->cpu);
     245                 :          0 :         ktime_get_ts(&ts); /* get high res monotonic timestamp */
     246                 :          0 :         ev->timestamp_ns = timespec_to_ns(&ts);
     247                 :          0 :         ev->what = PROC_EVENT_COMM;
     248                 :          0 :         ev->event_data.comm.process_pid  = task->pid;
     249                 :          0 :         ev->event_data.comm.process_tgid = task->tgid;
     250                 :          0 :         get_task_comm(ev->event_data.comm.comm, task);
     251                 :            : 
     252                 :          0 :         memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
     253                 :          0 :         msg->ack = 0; /* not used */
     254                 :          0 :         msg->len = sizeof(*ev);
     255                 :          0 :         msg->flags = 0; /* not used */
     256                 :          0 :         cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
     257                 :            : }
     258                 :            : 
     259                 :          0 : void proc_coredump_connector(struct task_struct *task)
     260                 :            : {
     261                 :            :         struct cn_msg *msg;
     262                 :            :         struct proc_event *ev;
     263                 :            :         __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
     264                 :            :         struct timespec ts;
     265                 :            : 
     266         [ -  + ]:         19 :         if (atomic_read(&proc_event_num_listeners) < 1)
     267                 :         19 :                 return;
     268                 :            : 
     269                 :            :         msg = buffer_to_cn_msg(buffer);
     270                 :            :         ev = (struct proc_event *)msg->data;
     271                 :          0 :         memset(&ev->event_data, 0, sizeof(ev->event_data));
     272                 :            :         get_seq(&msg->seq, &ev->cpu);
     273                 :          0 :         ktime_get_ts(&ts); /* get high res monotonic timestamp */
     274                 :          0 :         ev->timestamp_ns = timespec_to_ns(&ts);
     275                 :          0 :         ev->what = PROC_EVENT_COREDUMP;
     276                 :          0 :         ev->event_data.coredump.process_pid = task->pid;
     277                 :          0 :         ev->event_data.coredump.process_tgid = task->tgid;
     278                 :            : 
     279                 :          0 :         memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
     280                 :          0 :         msg->ack = 0; /* not used */
     281                 :          0 :         msg->len = sizeof(*ev);
     282                 :          0 :         msg->flags = 0; /* not used */
     283                 :          0 :         cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
     284                 :            : }
     285                 :            : 
     286                 :          0 : void proc_exit_connector(struct task_struct *task)
     287                 :            : {
     288                 :            :         struct cn_msg *msg;
     289                 :            :         struct proc_event *ev;
     290                 :            :         __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
     291                 :            :         struct timespec ts;
     292                 :            : 
     293         [ +  + ]:    1151924 :         if (atomic_read(&proc_event_num_listeners) < 1)
     294                 :    1151907 :                 return;
     295                 :            : 
     296                 :            :         msg = buffer_to_cn_msg(buffer);
     297                 :            :         ev = (struct proc_event *)msg->data;
     298                 :         17 :         memset(&ev->event_data, 0, sizeof(ev->event_data));
     299                 :            :         get_seq(&msg->seq, &ev->cpu);
     300                 :         17 :         ktime_get_ts(&ts); /* get high res monotonic timestamp */
     301                 :         17 :         ev->timestamp_ns = timespec_to_ns(&ts);
     302                 :         17 :         ev->what = PROC_EVENT_EXIT;
     303                 :         17 :         ev->event_data.exit.process_pid = task->pid;
     304                 :         17 :         ev->event_data.exit.process_tgid = task->tgid;
     305                 :         17 :         ev->event_data.exit.exit_code = task->exit_code;
     306                 :         17 :         ev->event_data.exit.exit_signal = task->exit_signal;
     307                 :            : 
     308                 :         17 :         memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
     309                 :         17 :         msg->ack = 0; /* not used */
     310                 :         17 :         msg->len = sizeof(*ev);
     311                 :         17 :         msg->flags = 0; /* not used */
     312                 :         17 :         cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
     313                 :            : }
     314                 :            : 
     315                 :            : /*
     316                 :            :  * Send an acknowledgement message to userspace
     317                 :            :  *
     318                 :            :  * Use 0 for success, EFOO otherwise.
     319                 :            :  * Note: this is the negative of conventional kernel error
     320                 :            :  * values because it's not being returned via syscall return
     321                 :            :  * mechanisms.
     322                 :            :  */
     323                 :          0 : static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
     324                 :            : {
     325                 :            :         struct cn_msg *msg;
     326                 :            :         struct proc_event *ev;
     327                 :            :         __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8);
     328                 :            :         struct timespec ts;
     329                 :            : 
     330         [ +  + ]:         10 :         if (atomic_read(&proc_event_num_listeners) < 1)
     331                 :          5 :                 return;
     332                 :            : 
     333                 :            :         msg = buffer_to_cn_msg(buffer);
     334                 :            :         ev = (struct proc_event *)msg->data;
     335                 :          5 :         memset(&ev->event_data, 0, sizeof(ev->event_data));
     336                 :          5 :         msg->seq = rcvd_seq;
     337                 :          5 :         ktime_get_ts(&ts); /* get high res monotonic timestamp */
     338                 :          5 :         ev->timestamp_ns = timespec_to_ns(&ts);
     339                 :          5 :         ev->cpu = -1;
     340                 :          5 :         ev->what = PROC_EVENT_NONE;
     341                 :          5 :         ev->event_data.ack.err = err;
     342                 :          5 :         memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
     343                 :          5 :         msg->ack = rcvd_ack + 1;
     344                 :          5 :         msg->len = sizeof(*ev);
     345                 :          5 :         msg->flags = 0; /* not used */
     346                 :          5 :         cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
     347                 :            : }
     348                 :            : 
     349                 :            : /**
     350                 :            :  * cn_proc_mcast_ctl
     351                 :            :  * @data: message sent from userspace via the connector
     352                 :            :  */
     353                 :          0 : static void cn_proc_mcast_ctl(struct cn_msg *msg,
     354                 :            :                               struct netlink_skb_parms *nsp)
     355                 :            : {
     356                 :            :         enum proc_cn_mcast_op *mc_op = NULL;
     357                 :            :         int err = 0;
     358                 :            : 
     359         [ +  - ]:         10 :         if (msg->len != sizeof(*mc_op))
     360                 :            :                 return;
     361                 :            : 
     362                 :            :         /* 
     363                 :            :          * Events are reported with respect to the initial pid
     364                 :            :          * and user namespaces so ignore requestors from
     365                 :            :          * other namespaces.
     366                 :            :          */
     367         [ +  - ]:         10 :         if ((current_user_ns() != &init_user_ns) ||
     368                 :         10 :             (task_active_pid_ns(current) != &init_pid_ns))
     369                 :            :                 return;
     370                 :            : 
     371                 :            :         /* Can only change if privileged. */
     372         [ +  - ]:         10 :         if (!capable(CAP_NET_ADMIN)) {
     373                 :            :                 err = EPERM;
     374                 :            :                 goto out;
     375                 :            :         }
     376                 :            : 
     377                 :            :         mc_op = (enum proc_cn_mcast_op *)msg->data;
     378      [ +  +  - ]:         10 :         switch (*mc_op) {
     379                 :            :         case PROC_CN_MCAST_LISTEN:
     380                 :            :                 atomic_inc(&proc_event_num_listeners);
     381                 :            :                 break;
     382                 :            :         case PROC_CN_MCAST_IGNORE:
     383                 :            :                 atomic_dec(&proc_event_num_listeners);
     384                 :            :                 break;
     385                 :            :         default:
     386                 :            :                 err = EINVAL;
     387                 :            :                 break;
     388                 :            :         }
     389                 :            : 
     390                 :            : out:
     391                 :         10 :         cn_proc_ack(err, msg->seq, msg->ack);
     392                 :            : }
     393                 :            : 
     394                 :            : /*
     395                 :            :  * cn_proc_init - initialization entry point
     396                 :            :  *
     397                 :            :  * Adds the connector callback to the connector driver.
     398                 :            :  */
     399                 :          0 : static int __init cn_proc_init(void)
     400                 :            : {
     401                 :          0 :         int err = cn_add_callback(&cn_proc_event_id,
     402                 :            :                                   "cn_proc",
     403                 :            :                                   &cn_proc_mcast_ctl);
     404         [ #  # ]:          0 :         if (err) {
     405                 :          0 :                 pr_warn("cn_proc failed to register\n");
     406                 :          0 :                 return err;
     407                 :            :         }
     408                 :            :         return 0;
     409                 :            : }
     410                 :            : 
     411                 :            : module_init(cn_proc_init);

Generated by: LCOV version 1.9