Secure some more commands which take a regexp from untrusted user input.

Namely todo.search, note.search, dunno.search.

Conflicts:

	plugins/Note/plugin.py
	plugins/Todo/plugin.py
	src/version.py
This commit is contained in:
Daniel Folkinshteyn 2011-08-12 18:10:41 -04:00 committed by Valentin Lorentz
parent 0e3002d1f8
commit 3fa45b3b5f
5 changed files with 29 additions and 3 deletions

View File

@ -42,6 +42,7 @@ import supybot.ircmsgs as ircmsgs
import supybot.plugins as plugins import supybot.plugins as plugins
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
from supybot import commands
from supybot.i18n import PluginInternationalization, internationalizeDocstring from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Note') _ = PluginInternationalization('Note')
@ -294,7 +295,8 @@ class Note(callbacks.Plugin):
own = to own = to
for (option, arg) in optlist: for (option, arg) in optlist:
if option == 'regexp': if option == 'regexp':
criteria.append(arg.search) criteria.append(lambda x: commands.regexp_wrapper(x, reobj=arg,
timeout=0.1, plugin_name = self.name(), fcn_name='search'))
elif option == 'sent': elif option == 'sent':
own = frm own = frm
if glob: if glob:

View File

@ -41,6 +41,7 @@ from supybot.commands import *
import supybot.plugins as plugins import supybot.plugins as plugins
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
from supybot import commands
from supybot.i18n import PluginInternationalization, internationalizeDocstring from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Todo') _ = PluginInternationalization('Todo')
@ -237,6 +238,8 @@ class Todo(callbacks.Plugin):
criteria = [] criteria = []
for (option, arg) in optlist: for (option, arg) in optlist:
if option == 'regexp': if option == 'regexp':
criteria.append(lambda x: commands.regexp_wrapper(x, reobj=arg,
timeout=0.1, plugin_name = self.name(), fcn_name='search'))
criteria.append(arg.search) criteria.append(arg.search)
for glob in globs: for glob in globs:
glob = utils.python.glob2re(glob) glob = utils.python.glob2re(glob)

View File

@ -50,6 +50,7 @@ import supybot.world as world
from supybot.commands import * from supybot.commands import *
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
from supybot import commands
## i think we don't need any of this with sqlite3 ## i think we don't need any of this with sqlite3
#try: #try:
@ -431,7 +432,9 @@ class ChannelIdDatabasePlugin(callbacks.Plugin):
if opt == 'by': if opt == 'by':
predicates.append(lambda r, arg=arg: r.by == arg.id) predicates.append(lambda r, arg=arg: r.by == arg.id)
elif opt == 'regexp': elif opt == 'regexp':
predicates.append(lambda r, arg=arg: arg.search(r.text)) predicates.append(lambda x: commands.regexp_wrapper(x.text, reobj=arg,
timeout=0.1, plugin_name = self.name(), fcn_name='search'))
#predicates.append(lambda r, arg=arg: arg.search(r.text))
if glob: if glob:
def globP(r, glob=glob.lower()): def globP(r, glob=glob.lower()):
return fnmatch.fnmatch(r.text.lower(), glob) return fnmatch.fnmatch(r.text.lower(), glob)

View File

@ -106,6 +106,24 @@ def process(f, *args, **kwargs):
v = "Error: " + str(v) v = "Error: " + str(v)
return v return v
def regexp_wrapper(s, reobj, timeout, plugin_name, fcn_name):
'''A convenient wrapper to stuff regexp search queries through a subprocess.
This is used because specially-crafted regexps can use exponential time
and hang the bot.'''
def re_bool(s, reobj):
"""Since we can't enqueue match objects into the multiprocessing queue,
we'll just wrap the function to return bools."""
if reobj.search(s) is not None:
return True
else:
return False
try:
v = process(re_bool, s, reobj, timeout=timeout, pn=plugin_name, cn=fcn_name)
return v
except ProcessTimeoutError:
return False
class UrlSnarfThread(world.SupyThread): class UrlSnarfThread(world.SupyThread):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
assert 'url' in kwargs assert 'url' in kwargs

View File

@ -1,3 +1,3 @@
"""stick the various versioning attributes in here, so we only have to change """stick the various versioning attributes in here, so we only have to change
them once.""" them once."""
version = '0.83.4.1+limnoria (2011-08-13T01:57:03+0200)' version = '0.83.4.1+limnoria (2011-08-13T01:59:18+0200)'