summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authordsmith <dsmith>2007-08-14 15:27:58 +0000
committerdsmith <dsmith>2007-08-14 15:27:58 +0000
commitb79aff3684e02d6f83a2fa2a2fcfe53d5c9d6d14 (patch)
treebb872eed2c44fbca889e0a068ecd964e86938f87 /runtime
parent5eddf13b73a01f3b334e5be80fc3cc1b312d1fea (diff)
downloadsystemtap-steved-b79aff3684e02d6f83a2fa2a2fcfe53d5c9d6d14.tar.gz
systemtap-steved-b79aff3684e02d6f83a2fa2a2fcfe53d5c9d6d14.tar.xz
systemtap-steved-b79aff3684e02d6f83a2fa2a2fcfe53d5c9d6d14.zip
2007-08-14 David Smith <dsmith@redhat.com>
Merge from setuid-branch. Changes also by Martin Hunt <hunt@redhat.com>. * control.c (_stp_ctl_write): Make sure we don't overflow. (_stp_ctl_open_cmd): Do not allow multiple opens of the control file. (_stp_ctl_write_cmd): Once STP_START is received, ignore everything except STP_EXIT. Create another state variable "initialized". Don't respond to STP_SYMBOLS or STP_MODULES unless initialized is 0. Also check that current pid is the same as the pid that did insmod. (_stp_register_ctl_channel): Bug fix - sets owner/group after checking for NULL. * procfs.c (_stp_ctl_write): Make sure we don't overflow. (_stp_ctl_open_cmd): Do not allow multiple opens of the control file. (_stp_ctl_write_cmd): Once STP_START is received, ignore everything except STP_EXIT. Create another state variable "initialized". Don't respond to STP_SYMBOLS or STP_MODULES unless initialized is 0. Also check that current pid is the same as the pid that did insmod. (_stp_register_ctl_channel): Set ownership of cmd file and percpu files for bulkmode. * relayfs.c (utt_trace_setup): Set ownership of percpu files. Improved error handling. (utt_trace_remove): Improved error checking. * utt.c (utt_remove_tree): Improved error checking. (utt_trace_cleanup): Ditto. (utt_create_buf_file_callback): Set file ownership. (utt_create_global_buf_file_callback): Set file ownership. * transport.h: Delcare _stp_uid, _stp_gid, and _stp_init_pid. * transport.c (_stp_transport_init): Set _stp_uid, _stp_gid, and _stp_init_pid.
Diffstat (limited to 'runtime')
-rw-r--r--runtime/transport/ChangeLog40
-rw-r--r--runtime/transport/control.c48
-rw-r--r--runtime/transport/procfs.c46
-rw-r--r--runtime/transport/relayfs.c35
-rw-r--r--runtime/transport/symbols.c41
-rw-r--r--runtime/transport/transport.c3
-rw-r--r--runtime/transport/transport.h4
-rw-r--r--runtime/transport/utt.c26
8 files changed, 186 insertions, 57 deletions
diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog
index 7ce5be44..ee476b29 100644
--- a/runtime/transport/ChangeLog
+++ b/runtime/transport/ChangeLog
@@ -1,3 +1,43 @@
+2007-08-14 David Smith <dsmith@redhat.com>
+
+ Merge from setuid-branch. Changes also by Martin Hunt
+ <hunt@redhat.com>.
+
+ * control.c (_stp_ctl_write): Make sure we don't overflow.
+ (_stp_ctl_open_cmd): Do not allow multiple opens of the control
+ file.
+ (_stp_ctl_write_cmd): Once STP_START is received, ignore
+ everything except STP_EXIT. Create another state variable
+ "initialized". Don't respond to STP_SYMBOLS or STP_MODULES unless
+ initialized is 0. Also check that current pid is the same as the
+ pid that did insmod.
+ (_stp_register_ctl_channel): Bug fix - sets owner/group after
+ checking for NULL.
+
+ * procfs.c (_stp_ctl_write): Make sure we don't overflow.
+ (_stp_ctl_open_cmd): Do not allow multiple opens of the control
+ file.
+ (_stp_ctl_write_cmd): Once STP_START is received, ignore
+ everything except STP_EXIT. Create another state variable
+ "initialized". Don't respond to STP_SYMBOLS or STP_MODULES unless
+ initialized is 0. Also check that current pid is the same as the
+ pid that did insmod.
+ (_stp_register_ctl_channel): Set ownership of cmd file and percpu
+ files for bulkmode.
+
+ * relayfs.c (utt_trace_setup): Set ownership of percpu files.
+ Improved error handling.
+ (utt_trace_remove): Improved error checking.
+
+ * utt.c (utt_remove_tree): Improved error checking.
+ (utt_trace_cleanup): Ditto.
+ (utt_create_buf_file_callback): Set file ownership.
+ (utt_create_global_buf_file_callback): Set file ownership.
+
+ * transport.h: Delcare _stp_uid, _stp_gid, and _stp_init_pid.
+ * transport.c (_stp_transport_init): Set _stp_uid, _stp_gid, and
+ _stp_init_pid.
+
2007-07-26 Martin Hunt <hunt@redhat.com>
Spotted by Ming Chang.
diff --git a/runtime/transport/control.c b/runtime/transport/control.c
index 68c3b9ae..1f7f70bd 100644
--- a/runtime/transport/control.c
+++ b/runtime/transport/control.c
@@ -21,6 +21,7 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
int type;
+ static int started = 0, initialized = 0;
if (count < sizeof(int))
return 0;
@@ -28,7 +29,7 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
if (get_user(type, (int __user *)buf))
return -EFAULT;
- //kbug ("count:%d type:%d\n", count, type);
+ // kbug ("count:%d type:%d\n", count, type);
if (type == STP_SYMBOLS) {
count -= sizeof(long);
@@ -41,20 +42,29 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
switch (type) {
case STP_START:
{
- struct _stp_msg_start st;
- if (count < sizeof(st))
- return 0;
- if (copy_from_user (&st, buf, sizeof(st)))
- return -EFAULT;
- _stp_handle_start (&st);
+ if (started == 0) {
+ struct _stp_msg_start st;
+ if (count < sizeof(st))
+ return 0;
+ if (copy_from_user (&st, buf, sizeof(st)))
+ return -EFAULT;
+ _stp_handle_start (&st);
+ started = 1;
+ }
break;
}
case STP_SYMBOLS:
- count = _stp_do_symbols(buf, count);
+ if (initialized == 0 && count && current->pid == _stp_init_pid)
+ count = _stp_do_symbols(buf, count);
break;
case STP_MODULE:
- count = _stp_do_module(buf, count);
+ if (initialized == 0 && current->pid == _stp_init_pid) {
+ if (count)
+ count = _stp_do_module(buf, count);
+ else
+ initialized = 1;
+ }
break;
case STP_EXIT:
_stp_exit_flag = 1;
@@ -73,11 +83,13 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
return count;
}
+#define STP_CTL_BUFFER_SIZE 256
+
struct _stp_buffer {
struct list_head list;
int len;
int type;
- char buf[256];
+ char buf[STP_CTL_BUFFER_SIZE];
};
static DECLARE_WAIT_QUEUE_HEAD(_stp_ctl_wq);
@@ -127,6 +139,10 @@ static int _stp_ctl_write (int type, void *data, unsigned len)
_stp_ctl_write_dbug(type, data, len);
#endif
+ /* make sure we won't overflow the buffer */
+ if (unlikely(len > STP_CTL_BUFFER_SIZE))
+ return 0;
+
numtrylock = 0;
while (!spin_trylock_irqsave (&_stp_pool_lock, flags) && (++numtrylock < MAXTRYLOCK))
ndelay (TRYLOCKDELAY);
@@ -145,7 +161,7 @@ static int _stp_ctl_write (int type, void *data, unsigned len)
spin_unlock_irqrestore(&_stp_pool_lock, flags);
bptr->type = type;
- memcpy(bptr->buf, data, min((size_t) len, sizeof(bptr->buf)));
+ memcpy(bptr->buf, data, len);
bptr->len = len;
/* put it on the pool of ready buffers */
@@ -215,17 +231,23 @@ _stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *pp
return len;
}
+static int _stp_ctl_opens = 0;
static int _stp_ctl_open_cmd (struct inode *inode, struct file *file)
{
+ if (_stp_ctl_opens)
+ return -1;
+
+ _stp_ctl_opens++;
_stp_pid = current->pid;
return 0;
}
static int _stp_ctl_close_cmd (struct inode *inode, struct file *file)
{
+ if (_stp_ctl_opens)
+ _stp_ctl_opens--;
_stp_pid = 0;
return 0;
-
}
static struct file_operations _stp_ctl_fops_cmd = {
@@ -267,6 +289,8 @@ static int _stp_register_ctl_channel (void)
_stp_cmd_file = debugfs_create_file("cmd", 0600, _stp_utt->dir, NULL, &_stp_ctl_fops_cmd);
if (_stp_cmd_file == NULL)
goto err0;
+ _stp_cmd_file->d_inode->i_uid = _stp_uid;;
+ _stp_cmd_file->d_inode->i_gid = _stp_gid;
return 0;
err0:
diff --git a/runtime/transport/procfs.c b/runtime/transport/procfs.c
index 36920707..ca07660f 100644
--- a/runtime/transport/procfs.c
+++ b/runtime/transport/procfs.c
@@ -67,6 +67,7 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
int type;
+ static int started = 0, initialized = 0;
if (count < sizeof(int))
return 0;
@@ -87,20 +88,29 @@ static ssize_t _stp_ctl_write_cmd (struct file *file, const char __user *buf,
switch (type) {
case STP_START:
{
- struct _stp_msg_start st;
- if (count < sizeof(st))
- return 0;
- if (copy_from_user (&st, buf, sizeof(st)))
- return -EFAULT;
- _stp_handle_start (&st);
+ if (started == 0) {
+ struct _stp_msg_start st;
+ if (count < sizeof(st))
+ return 0;
+ if (copy_from_user (&st, buf, sizeof(st)))
+ return -EFAULT;
+ _stp_handle_start (&st);
+ started = 1;
+ }
break;
}
case STP_SYMBOLS:
- count = _stp_do_symbols(buf, count);
+ if (initialized == 0 && count && current->pid == _stp_init_pid)
+ count = _stp_do_symbols(buf, count);
break;
case STP_MODULE:
- count = _stp_do_module(buf, count);
+ if (initialized == 0 && current->pid == _stp_init_pid) {
+ if (count)
+ count = _stp_do_module(buf, count);
+ else
+ initialized = 1;
+ }
break;
case STP_EXIT:
_stp_exit_flag = 1;
@@ -151,6 +161,10 @@ static int _stp_ctl_write (int type, void *data, int len)
spin_unlock_irqrestore(&_stp_ready_lock, flags);
#endif
+ /* make sure we won't overflow the buffer */
+ if (unlikely(len > STP_BUFFER_SIZE))
+ return 0;
+
numtrylock = 0;
while (!spin_trylock_irqsave (&_stp_pool_lock, flags) && (++numtrylock < MAXTRYLOCK))
ndelay (TRYLOCKDELAY);
@@ -237,17 +251,23 @@ _stp_ctl_read_cmd (struct file *file, char __user *buf, size_t count, loff_t *pp
return len;
}
+static int _stp_ctl_opens = 0;
static int _stp_ctl_open_cmd (struct inode *inode, struct file *file)
{
+ if (_stp_ctl_opens)
+ return -1;
+
+ _stp_ctl_opens++;
_stp_pid = current->pid;
return 0;
}
static int _stp_ctl_close_cmd (struct inode *inode, struct file *file)
{
+ if (_stp_ctl_opens)
+ _stp_ctl_opens--;
_stp_pid = 0;
return 0;
-
}
static struct file_operations _stp_proc_fops_cmd = {
@@ -378,9 +398,11 @@ static int _stp_register_ctl_channel (void)
/* now for each cpu "n", create /proc/systemtap/module_name/n */
for_each_cpu(i) {
sprintf(buf, "%d", i);
- de = create_proc_entry (buf, S_IFREG|S_IRUSR, _stp_proc_mod);
+ de = create_proc_entry (buf, 0600, _stp_proc_mod);
if (de == NULL)
goto err1;
+ de->uid = _stp_uid;
+ de->gid = _stp_gid;
de->proc_fops = &_stp_proc_fops;
de->data = _stp_kmalloc(sizeof(int));
if (de->data == NULL) {
@@ -393,9 +415,11 @@ static int _stp_register_ctl_channel (void)
#endif /* STP_BULKMODE */
/* finally create /proc/systemtap/module_name/cmd */
- de = create_proc_entry ("cmd", S_IFREG|S_IRUSR|S_IWUSR, _stp_proc_mod);
+ de = create_proc_entry ("cmd", 0600, _stp_proc_mod);
if (de == NULL)
goto err1;
+ de->uid = _stp_uid;
+ de->gid = _stp_gid;
de->proc_fops = &_stp_proc_fops_cmd;
return 0;
diff --git a/runtime/transport/relayfs.c b/runtime/transport/relayfs.c
index 2615145c..28bb0e65 100644
--- a/runtime/transport/relayfs.c
+++ b/runtime/transport/relayfs.c
@@ -80,14 +80,15 @@ static void _stp_remove_relay_root(struct dentry *root)
struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts)
{
struct utt_trace *utt;
+ int i;
utt = _stp_kzalloc(sizeof(*utt));
if (!utt)
return NULL;
- utt->utt_tree_root = _stp_get_root_dir(utts->root);
+ utt->utt_tree_root = _stp_get_root_dir(utts->root);
if (!utt->utt_tree_root)
- return NULL;
+ goto err;
utt->dir = relayfs_create_dir(utts->name, utt->utt_tree_root);
if (!utt->dir)
@@ -95,20 +96,29 @@ struct utt_trace *utt_trace_setup(struct utt_trace_setup *utts)
kbug("relay_open %d %d\n", utts->buf_size, utts->buf_nr);
- utt->rchan = relay_open("trace", utt->dir, utts->buf_size, utts->buf_nr, 0, &stp_rchan_callbacks);
+ utt->rchan = relay_open("trace", utt->dir, utts->buf_size,
+ utts->buf_nr, 0, &stp_rchan_callbacks);
if (!utt->rchan)
- goto err1;
+ goto err;
+
+ /* now set ownership */
+ for_each_online_cpu(i) {
+ utt->rchan->buf[i]->dentry->d_inode->i_uid = _stp_uid;
+ utt->rchan->buf[i]->dentry->d_inode->i_gid = _stp_gid;
+ }
utt->rchan->private_data = utt;
utt->trace_state = Utt_trace_setup;
utts->err = 0;
return utt;
-err1:
- errk("couldn't create relay channel.\n");
- _stp_remove_relay_dir(utt->dir);
err:
- _stp_remove_relay_root(utt->utt_tree_root);
+ errk("couldn't create relay channel.\n");
+ if (utt->dir)
+ _stp_remove_relay_dir(utt->dir);
+ if (utt->utt_tree_root)
+ _stp_remove_relay_root(utt->utt_tree_root);
+ kfree(utt);
return NULL;
}
@@ -151,9 +161,12 @@ int utt_trace_remove(struct utt_trace *utt)
{
kbug("removing relayfs files. %d\n", utt->trace_state);
if (utt && (utt->trace_state == Utt_trace_setup || utt->trace_state == Utt_trace_stopped)) {
- relay_close(utt->rchan);
- _stp_remove_relay_dir(utt->dir);
- _stp_remove_relay_root(utt->utt_tree_root);
+ if (utt->rchan)
+ relay_close(utt->rchan);
+ if (utt->dir)
+ _stp_remove_relay_dir(utt->dir);
+ if (utt->utt_tree_root)
+ _stp_remove_relay_root(utt->utt_tree_root);
kfree(utt);
}
return 0;
diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c
index 323b4872..1d930183 100644
--- a/runtime/transport/symbols.c
+++ b/runtime/transport/symbols.c
@@ -104,6 +104,26 @@ static struct _stp_module * _stp_alloc_module_from_module (struct module *m)
return _stp_alloc_module(num, datasize);
}
+static void _stp_free_module(struct _stp_module *mod)
+{
+ /* free symbol memory */
+ if (mod->num_symbols) {
+ if (mod->allocated & 1)
+ vfree(mod->symbols);
+ else
+ kfree(mod->symbols);
+ if (mod->allocated & 2)
+ vfree(mod->symbol_data);
+ else
+ kfree(mod->symbol_data);
+ }
+ if (mod->sections)
+ kfree(mod->sections);
+
+ /* free module memory */
+ kfree(mod);
+}
+
/* Delete a module and free its memory. */
/* The lock should already be held before calling this. */
static void _stp_del_module(struct _stp_module *mod)
@@ -134,23 +154,8 @@ static void _stp_del_module(struct _stp_module *mod)
_stp_modules_by_addr[i] = _stp_modules_by_addr[i+1];
_stp_num_modules--;
-
- /* free symbol memory */
- if (mod->num_symbols) {
- if (mod->allocated & 1)
- vfree(mod->symbols);
- else
- kfree(mod->symbols);
- if (mod->allocated & 2)
- vfree(mod->symbol_data);
- else
- kfree(mod->symbol_data);
- }
- if (mod->sections)
- kfree(mod->sections);
- /* free module memory */
- kfree(mod);
+ _stp_free_module(mod);
}
static void _stp_free_modules(void)
@@ -471,8 +476,10 @@ static int _stp_do_module(const char __user *buf, int count)
return 0;
}
- if (_stp_ins_module(mod) < 0)
+ if (_stp_ins_module(mod) < 0) {
+ _stp_free_module(mod);
return -ENOMEM;
+ }
return count;
}
diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c
index e2737dd6..8df73ed5 100644
--- a/runtime/transport/transport.c
+++ b/runtime/transport/transport.c
@@ -223,6 +223,9 @@ int _stp_transport_init(void)
int ret;
kbug("transport_init\n");
+ _stp_init_pid = current->pid;
+ _stp_uid = current->uid;
+ _stp_gid = current->gid;
if (_stp_bufsize) {
unsigned size = _stp_bufsize * 1024 * 1024;
diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h
index d1e97edb..78b01181 100644
--- a/runtime/transport/transport.h
+++ b/runtime/transport/transport.h
@@ -23,5 +23,7 @@ static struct dentry *_stp_get_root_dir(const char *name);
static int _stp_lock_debugfs(void);
static void _stp_unlock_debugfs(void);
int _stp_pid = 0;
-
+uid_t _stp_uid = 0;
+gid_t _stp_gid = 0;
+pid_t _stp_init_pid = 0;
#endif /* _TRANSPORT_TRANSPORT_H_ */
diff --git a/runtime/transport/utt.c b/runtime/transport/utt.c
index 2389ccac..1ca59592 100644
--- a/runtime/transport/utt.c
+++ b/runtime/transport/utt.c
@@ -45,6 +45,8 @@ static void utt_remove_root(struct utt_trace *utt)
static void utt_remove_tree(struct utt_trace *utt)
{
+ if (utt == NULL || utt->dir == NULL)
+ return;
debugfs_remove(utt->dir);
utt_remove_root(utt);
}
@@ -65,7 +67,6 @@ static struct dentry *utt_create_tree(struct utt_trace *utt, const char *root, c
dir = debugfs_create_dir(name, utt->utt_tree_root);
if (!dir)
utt_remove_root(utt);
-
err:
return dir;
}
@@ -73,8 +74,12 @@ err:
void utt_trace_cleanup(struct utt_trace *utt)
{
- relay_close(utt->rchan);
- debugfs_remove(utt->dropped_file);
+ if (utt == NULL)
+ return;
+ if (utt->rchan)
+ relay_close(utt->rchan);
+ if (utt->dropped_file)
+ debugfs_remove(utt->dropped_file);
utt_remove_tree(utt);
kfree(utt);
}
@@ -144,8 +149,13 @@ static struct dentry *utt_create_buf_file_callback(const char *filename,
struct rchan_buf *buf,
int *is_global)
{
- return debugfs_create_file(filename, mode, parent, buf,
+ struct dentry *file = debugfs_create_file(filename, mode, parent, buf,
&relay_file_operations);
+ if (file) {
+ file->d_inode->i_uid = _stp_uid;
+ file->d_inode->i_gid = _stp_gid;
+ }
+ return file;
}
static struct dentry *utt_create_global_buf_file_callback(const char *filename,
@@ -154,9 +164,15 @@ static struct dentry *utt_create_global_buf_file_callback(const char *filename,
struct rchan_buf *buf,
int *is_global)
{
+ struct dentry *file;
*is_global = 1;
- return debugfs_create_file(filename, mode, parent, buf,
+ file = debugfs_create_file(filename, mode, parent, buf,
&relay_file_operations);
+ if (file) {
+ file->d_inode->i_uid = _stp_uid;
+ file->d_inode->i_gid = _stp_gid;
+ }
+ return file;
}
static struct rchan_callbacks utt_relay_callbacks = {