Skip to content

Commit 7dd78ef

Browse files
author
Release Manager
committed
Trac #2877: security risk -- restrict the input of eval in CC constructor
There are valid uses for eval() and sage_eval(), it makes it much easier to parse output from interfaces for example. It is difficult (if not impossible) to completely sanitize arbitrary input, but one should be able to (say) write a backend that takes specific data, calls on Sage to process it, and then returns the result. For example, I might want a webpage that uses Sage to compute Julia sets, and takes as input a complex number. That the following work is scary {{{ sage: CC("os.getpid()") 10324.0000000000 sage: CC("os.mkdir('a')") NaN - NaN*I sage: CC("os.rmdir('a')") NaN - NaN*I sage: CC("os.exec(...)") }}} In this ticket, one introduces restrictions on the text input to CC that prevent most of these terrible examples. URL: https://trac.sagemath.org/2877 Reported by: robertwb Ticket author(s): Frédéric Chapoton Reviewer(s): Travis Scrimshaw, Kwankyu Lee
2 parents cf1a7a5 + 57e8e9b commit 7dd78ef

File tree

3 files changed

+29
-12
lines changed

3 files changed

+29
-12
lines changed

src/sage/interfaces/singular.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,10 +1576,10 @@ def sage_global_ring(self):
15761576
''
15771577
sage: R = singular('r5').sage_global_ring(); R
15781578
Multivariate Polynomial Ring in a, b, c over Complex Field with 54 bits of precision
1579-
sage: R.base_ring()('j')
1579+
sage: R.base_ring()('k')
15801580
Traceback (most recent call last):
15811581
...
1582-
NameError: name 'j' is not defined
1582+
ValueError: given string 'k' is not a complex number
15831583
sage: R.base_ring()('I')
15841584
1.00000000000000*I
15851585

src/sage/rings/complex_mpfr.pyx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,15 +500,31 @@ class ComplexField_class(sage.rings.abc.ComplexField):
500500
sage: CC(i)
501501
1.00000000000000*I
502502
503+
TESTS::
504+
505+
sage: CC('1.2+3.4*j')
506+
1.20000000000000 + 3.40000000000000*I
507+
sage: CC('hello')
508+
Traceback (most recent call last):
509+
...
510+
ValueError: given string 'hello' is not a complex number
503511
"""
504512
if not isinstance(x, (RealNumber, tuple)):
505513
if isinstance(x, ComplexDoubleElement):
506514
return ComplexNumber(self, x.real(), x.imag())
507515
elif isinstance(x, str):
516+
x = x.replace(' ', '')
517+
x = x.replace('i', 'I')
518+
x = x.replace('j', 'I')
519+
x = x.replace('E', 'e')
520+
allowed = '+-.*0123456789Ie'
521+
if not all(letter in allowed for letter in x):
522+
raise ValueError(f'given string {x!r} is not a complex number')
523+
# This should rather use a proper parser to validate input.
508524
# TODO: this is probably not the best and most
509525
# efficient way to do this. -- Martin Albrecht
510526
return ComplexNumber(self,
511-
sage_eval(x.replace(' ',''), locals={"I":self.gen(),"i":self.gen()}))
527+
sage_eval(x, locals={"I": self.gen()}))
512528

513529
late_import()
514530
if isinstance(x, NumberFieldElement_quadratic):

src/sage/schemes/elliptic_curves/period_lattice.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,12 @@ def __init__(self, E, embedding=None):
204204
K = E.base_field()
205205
if embedding is None:
206206
embs = K.embeddings(AA)
207-
real = len(embs)>0
207+
real = len(embs) > 0
208208
if not real:
209209
embs = K.embeddings(QQbar)
210210
embedding = embs[0]
211211
else:
212-
embedding = refine_embedding(embedding,Infinity)
212+
embedding = refine_embedding(embedding, Infinity)
213213
real = embedding(K.gen()).imag().is_zero()
214214

215215
self.embedding = embedding
@@ -1802,7 +1802,7 @@ def elliptic_exponential(self, z, to_curve=True):
18021802
z = C(z)
18031803
z_is_real = z.is_real()
18041804
except TypeError:
1805-
raise TypeError("%s is not a complex number"%z)
1805+
raise TypeError("%s is not a complex number" % z)
18061806
prec = C.precision()
18071807

18081808
# test for the point at infinity:
@@ -1813,7 +1813,7 @@ def elliptic_exponential(self, z, to_curve=True):
18131813
if to_curve:
18141814
return self.curve().change_ring(K)(0)
18151815
else:
1816-
return (K('+infinity'), K('+infinity'))
1816+
return K(Infinity), K(Infinity)
18171817

18181818
# general number field code (including QQ):
18191819

@@ -1830,7 +1830,7 @@ def elliptic_exponential(self, z, to_curve=True):
18301830
# the same precision as the input.
18311831

18321832
x, y = pari(self.basis(prec=prec)).ellwp(z, flag=1)
1833-
x, y = [C(t) for t in (x,y)]
1833+
x, y = [C(t) for t in (x, y)]
18341834

18351835
if self.real_flag and z_is_real:
18361836
x = x.real()
@@ -1839,14 +1839,15 @@ def elliptic_exponential(self, z, to_curve=True):
18391839
if to_curve:
18401840
K = x.parent()
18411841
v = refine_embedding(self.embedding, Infinity)
1842-
a1,a2,a3,a4,a6 = [K(v(a)) for a in self.E.ainvs()]
1842+
a1, a2, a3, a4, a6 = [K(v(a)) for a in self.E.ainvs()]
18431843
b2 = K(v(self.E.b2()))
18441844
x = x - b2 / 12
18451845
y = (y - (a1 * x + a3)) / 2
1846-
EK = EllipticCurve(K,[a1,a2,a3,a4,a6])
1847-
return EK.point((x,y,K(1)), check=False)
1846+
EK = EllipticCurve(K, [a1, a2, a3, a4, a6])
1847+
return EK.point((x, y, K.one()), check=False)
18481848
else:
1849-
return (x,y)
1849+
return (x, y)
1850+
18501851

18511852
def reduce_tau(tau):
18521853
r"""

0 commit comments

Comments
 (0)