From: dsmith Date: Tue, 14 Aug 2007 15:27:58 +0000 (+0000) Subject: 2007-08-14 David Smith X-Git-Tag: release-0.6~321 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=b79aff3684e02d6f83a2fa2a2fcfe53d5c9d6d14;p=systemtap.git 2007-08-14 David Smith Merge from setuid-branch. Changes also by Martin Hunt . * 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. --- diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog index 7ce5be443..ee476b29a 100644 --- a/runtime/transport/ChangeLog +++ b/runtime/transport/ChangeLog @@ -1,3 +1,43 @@ +2007-08-14 David Smith + + Merge from setuid-branch. Changes also by Martin Hunt + . + + * 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 Spotted by Ming Chang. diff --git a/runtime/transport/control.c b/runtime/transport/control.c index 68c3b9ae8..1f7f70bdf 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 36920707a..ca07660f9 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 2615145ca..28bb0e657 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 323b48724..1d930183f 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 e2737dd6a..8df73ed5a 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 d1e97edbc..78b011810 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 2389ccace..1ca595924 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 = {