CVE-2020-28975: Insufficient Information (NVD-CWE-noinfo)
value: svm_predict_values in svm.cpp in Libsvm v324, as used in scikit-learn 0.23.2 and other products, allows attackers to cause a denial of service (segmentation fault) via a crafted model SVM (introduced via pickle, json, or any other model permanence standard) with a large value in the _n_support array. NOTE: the scikit-learn vendor's position is that the behavior can only occur if the library's API is violated by an application that changes a private attribute.
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
CVSS v3 base score: 7.5
Published: 2020-11-21T21:15Z
Repository: https://github.com/scikit-learn/scikit-learn
Language: Python
Files changed: doc/whats_new/v1.0.rst, sklearn/svm/_base.py, sklearn/svm/tests/test_svm.py
Commit date: 2021-10-20 14:30:06 +0200
Commit message: FIX Prevents segfault in SVC when internals are altered (#21336)

Co-authored-by: Guillaume Lemaitre <g.lemaitre58@gmail.com>
Co-authored-by: Jérémie du Boisberranger <34657725+jeremiedbb@users.noreply.github.com>
Co-authored-by: Olivier Grisel <olivier.grisel@gmail.com>
Diff: diff --git a/doc/whats_new/v1.0.rst b/doc/whats_new/v1.0.rst
index 40076c0b2..30c184db5 100644
--- a/doc/whats_new/v1.0.rst
+++ b/doc/whats_new/v1.0.rst
@@ -65,10 +65,19 @@ Fixed models
 
 - |Fix| :meth:`pipeline.Pipeline.get_feature_names_out` correctly passes feature
   names out from one step of a pipeline to the next. :pr:`21351` by
   `Thomas Fan`_.
 
+:mod:`sklearn.svm`
+..................
+
+- |Fix| :class:`svm.SVC` and :class:`svm.SVR` check for an inconsistency
+  in its internal representation and raise an error instead of segfaulting.
+  This fix also resolves
+  `CVE-2020-28975 <https://nvd.nist.gov/vuln/detail/CVE-2020-28975>`__.
+  :pr:`21336` by `Thomas Fan`_.
+
 .. _changes_1_0:
 
 Version 1.0.0
 =============
 
diff --git a/sklearn/svm/_base.py b/sklearn/svm/_base.py
index 9c992e0d1..7f0e628aa 100644
--- a/sklearn/svm/_base.py
+++ b/sklearn/svm/_base.py
@@ -614,10 +614,17 @@ class BaseLibSVM(BaseEstimator, metaclass=ABCMeta):
                 raise ValueError(
                     "X.shape[1] = %d should be equal to %d, "
                     "the number of samples at training time"
                     % (X.shape[1], self.shape_fit_[0])
                 )
+        # Fixes https://nvd.nist.gov/vuln/detail/CVE-2020-28975
+        # Check that _n_support is consistent with support_vectors
+        sv = self.support_vectors_
+        if not self._sparse and sv.size > 0 and self.n_support_.sum() != sv.shape[0]:
+            raise ValueError(
+                f"The internal representation of {self.__class__.__name__} was altered"
+            )
         return X
 
     @property
     def coef_(self):
         """Weights assigned to the features when `kernel="linear"`.
diff --git a/sklearn/svm/tests/test_svm.py b/sklearn/svm/tests/test_svm.py
index 3933b6ca0..eb15aca00 100644
--- a/sklearn/svm/tests/test_svm.py
+++ b/sklearn/svm/tests/test_svm.py
@@ -1369,5 +1369,18 @@ def test_custom_kernel_not_array_input(Estimator):
         assert_array_equal(svc1.predict(data), svc2.predict(X))
         assert_array_equal(svc1.predict(data), svc3.predict(K))
     else:  # regressor
         assert_allclose(svc1.predict(data), svc2.predict(X))
         assert_allclose(svc1.predict(data), svc3.predict(K))
+
+
+def test_svc_raises_error_internal_representation():
+    """Check that SVC raises error when internal representation is altered.
+
+    Non-regression test for #18891 and https://nvd.nist.gov/vuln/detail/CVE-2020-28975
+    """
+    clf = svm.SVC(kernel="linear").fit(X, Y)
+    clf._n_support[0] = 1000000
+
+    msg = "The internal representation of SVC was altered"
+    with pytest.raises(ValueError, match=msg):
+        clf.predict(X)

Fixed code: :mod:`sklearn.svm`
..................

- |Fix| :class:`svm.SVC` and :class:`svm.SVR` check for an inconsistency
  in its internal representation and raise an error instead of segfaulting.
  This fix also resolves
  `CVE-2020-28975 <https://nvd.nist.gov/vuln/detail/CVE-2020-28975>`__.
  :pr:`21336` by `Thomas Fan`_.

        # Fixes https://nvd.nist.gov/vuln/detail/CVE-2020-28975
        # Check that _n_support is consistent with support_vectors
        sv = self.support_vectors_
        if not self._sparse and sv.size > 0 and self.n_support_.sum() != sv.shape[0]:
            raise ValueError(
                f"The internal representation of {self.__class__.__name__} was altered"
            )


def test_svc_raises_error_internal_representation():
    """Check that SVC raises error when internal representation is altered.

    Non-regression test for #18891 and https://nvd.nist.gov/vuln/detail/CVE-2020-28975
    """
    clf = svm.SVC(kernel="linear").fit(X, Y)
    clf._n_support[0] = 1000000

    msg = "The internal representation of SVC was altered"
    with pytest.raises(ValueError, match=msg):
        clf.predict(X)