Index: core/user.inc
===================================================================
--- core/user.inc	(revision 2169)
+++ core/user.inc	(working copy)
@@ -48,6 +48,7 @@
       }
 
       // rebuild the permission string
+      $permissions = _update_api_escape_permissions($permissions);
       $updated_permissions = implode(', ', $permissions);
       $ret[] = update_sql("UPDATE {permission} SET perm = '$updated_permissions' WHERE rid = {$role->rid}");
     }
@@ -57,6 +58,7 @@
         $permissions[] = trim($permission);
       }
       // rebuild the permission string
+      $permissions = _update_api_escape_permissions($permissions);
       $updated_permissions = implode(', ', $permissions);
       $ret[] = update_sql("INSERT INTO {permission} (rid, perm, tid) VALUES({$role->rid},'$updated_permissions',0)");
     }
@@ -83,6 +85,7 @@
       }
       
       // rebuild the permission string
+      $permissions = _update_api_escape_permissions($permissions);
       $updated_permissions = implode(', ', $permissions);
       $ret[] = update_sql("UPDATE {permission} SET perm = '$update_permissions' WHERE rid = {$role->rid}");
     }
@@ -111,3 +114,22 @@
   }
   return $permissions;
 }
+
+/**
+ * Escape an array of permissions. Some modules define permissions containing
+ * single quotes; e.g., the module_grants defines the permission
+ * "access 'I can edit' tab"
+ * 
+ * @param $permissions
+ *   An array of permissions
+ *   
+ * @return 
+ *   An array of values escaped for use in SQL string literals
+ */
+function _update_api_escape_permissions($permissions) {
+  $result = array();
+  foreach ($permissions as $perm) {
+    $result[] = str_replace("'", "''", $perm);
+  }
+  return $result;
+}
