Revert 10521, 10526 and 10527. This completes reversion of ACM modifications to xm.

Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
kfraser@dhcp93.uk.xensource.com committed 2006-06-30 13:33:20 +01:00
1 parent ae9bfcdced
commit 7550e5d3f9
9 files changed
+35 -752

No files matched your search

-102
View File
@@ -14,7 +14,6 @@
#============================================================================
# Copyright (C) 2006 International Business Machines Corp.
# Author: Reiner Sailer
# Author: Bryan D. Payne <bdpayne@us.ibm.com>
#============================================================================
import commands
@@ -22,14 +21,11 @@ import logging
import sys, os, string, re
import traceback
import shutil
#from xml.marshal import generic
from xen.lowlevel import acm
from xen.xend import sxp
from xen.xend.XendLogging import log
#global directories and tools for security management
policy_dir_prefix = "/etc/xen/acm-security/policies"
res_label_filename = policy_dir_prefix + "/resource_labels"
boot_filename = "/boot/grub/menu.lst"
xensec_xml2bin = "/usr/sbin/xensec_xml2bin"
xensec_tool = "/usr/sbin/xensec_tool"
@@ -534,101 +530,3 @@ def list_labels(policy_name, condition):
if label not in labels:
labels.append(label)
return labels
def get_res_label(resource):
"""Returns resource label information (label, policy) if it exists.
Otherwise returns null label and policy.
"""
def default_res_label():
ssidref = NULL_SSIDREF
if on():
label = ssidref2label(ssidref)
else:
label = None
return (label, 'NULL')
(label, policy) = default_res_label()
# load the resource label file
configfile = res_label_filename
if not os.path.isfile(configfile):
log.info("Resource label file not found.")
return default_res_label()
#
# Commented out pending replacement for xml.marshal.generic
#
# fd = open(configfile, "rb")
# res_label_cache = generic.load(fd)
# fd.close()
# # find the resource information
# if res_label_cache.has_key(resource):
# (policy, label) = res_label_cache[resource]
return (label, policy)
def get_res_security_details(resource):
"""Returns the (label, ssidref, policy) associated with a given
resource from the global resource label file.
"""
def default_security_details():
ssidref = NULL_SSIDREF
if on():
label = ssidref2label(ssidref)
else:
label = None
policy = active_policy
return (label, ssidref, policy)
(label, ssidref, policy) = default_security_details()
# find the entry associated with this resource
(label, policy) = get_res_label(resource)
if policy == 'NULL':
log.info("Resource label for "+resource+" not in file, using DEFAULT.")
return default_security_details()
# is this resource label for the running policy?
if policy == active_policy:
ssidref = label2ssidref(label, policy, 'res')
else:
log.info("Resource label not for active policy, using DEFAULT.")
return default_security_details()
return (label, ssidref, policy)
def res_security_check(resource, domain_label):
"""Checks if the given resource can be used by the given domain
label. Returns 1 if the resource can be used, otherwise 0.
"""
rtnval = 1
# if security is on, ask the hypervisor for a decision
if on():
(label, ssidref, policy) = get_res_security_details(resource)
domac = ['access_control']
domac.append(['policy', active_policy])
domac.append(['label', domain_label])
domac.append(['type', 'dom'])
decision = get_decision(domac, ['ssidref', str(ssidref)])
# provide descriptive error messages
if decision == 'DENIED':
if label == ssidref2label(NULL_SSIDREF):
raise ACMError("Resource '"+resource+"' is not labeled")
rtnval = 0
else:
raise ACMError("Permission denied for resource '"+resource+"' because label '"+label+"' is not allowed")
rtnval = 0
# security is off, make sure resource isn't labeled
else:
(label, policy) = get_res_label(resource)
if policy != 'NULL':
raise ACMError("Security is off, but '"+resource+"' is labeled")
rtnval = 0
return rtnval
+2 -10
View File
@@ -21,7 +21,6 @@ import re
import string
from xen.util import blkif
from xen.util import security
from xen.xend import sxp
from xen.xend.XendError import VmError
@@ -41,22 +40,15 @@ class BlkifController(DevController):
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
uname = sxp.child_value(config, 'uname')
dev = sxp.child_value(config, 'dev')
(typ, params) = string.split(uname, ':', 1)
(typ, params) = string.split(sxp.child_value(config, 'uname'), ':', 1)
back = { 'dev' : dev,
'type' : typ,
'params' : params,
'mode' : sxp.child_value(config, 'mode', 'r')
}
if security.on():
(label, ssidref, policy) = security.get_res_security_details(uname)
back.update({'acm_label' : label,
'acm_ssidref': str(ssidref),
'acm_policy' : policy})
}
if 'ioemu:' in dev:
(dummy, dev1) = string.split(dev, ':', 1)
+29 -124
View File
@@ -14,156 +14,61 @@
#============================================================================
# Copyright (C) 2006 International Business Machines Corp.
# Author: Reiner Sailer <sailer@us.ibm.com>
# Author: Bryan D. Payne <bdpayne@us.ibm.com>
#============================================================================
"""Labeling a domain configuration file or a resoruce.
"""Labeling a domain configuration file.
"""
import sys, os
import string
import traceback
#from xml.marshal import generic
from xen.util import security
from xen.util.security import ACMError, err, active_policy, label2ssidref, on, access_control_re
def usage():
print "\nUsage: xm addlabel <label> dom <configfile> [<policy>]"
print " xm addlabel <label> res <resource> [<policy>]\n"
print " This program adds an acm_label entry into the 'configfile'"
print " for a domain or to the global resource label file for a"
print " resource. It derives the policy from the running hypervisor"
print " if it is not given (optional parameter). If a label already"
print " exists for the given domain or resource, then addlabel fails.\n"
security.err("Usage")
print "\nUsage: xm addlabel <configfile> <label> [<policy>]\n"
print " This program adds an acm_label entry into the 'configfile'."
print " It derives the policy from the running hypervisor if it"
print " is not given (optional parameter). If the configfile is"
print " already labeled, then addlabel fails.\n"
err("Usage")
def validate_config_file(configfile):
"""Performs a simple sanity check on the configuration file passed on
the command line. We basically just want to make sure that it's
not a domain image file so we check for a few configuration values
and then we are satisfied. Returned 1 on success, otherwise 0.
"""
# read in the config file
globs = {}
locs = {}
def main(argv):
try:
execfile(configfile, globs, locs)
except:
print "Invalid configuration file."
return 0
policyref = None
if len(argv) not in [3,4]:
usage()
configfile = argv[1]
label = argv[2]
# sanity check on the data from the file
count = 0
required = ['kernel', 'memory', 'name']
for (k, v) in locs.items():
if k in required:
count += 1
if count != 3:
print "Invalid configuration file."
return 0
else:
return 1
def add_resource_label(label, resource, policyref):
"""Adds a resource label to the global resource label file.
"""
try:
# sanity check: make sure this label can be instantiated later on
ssidref = security.label2ssidref(label, policyref, 'res')
# sanity check on resource name
(type, file) = resource.split(":")
if type == "phy":
file = "/dev/" + file
if not os.path.exists(file):
print "Invalid resource '"+resource+"'"
return
# see if this resource is already in the file
file = security.res_label_filename
if not os.path.isfile(file):
print "Resource file not found, creating new file at:"
print "%s" % (file)
fd = open(file, "w")
fd.close();
access_control = {}
if len(argv) == 4:
policyref = argv[3]
elif on():
policyref = active_policy
else:
fd = open(file, "rb")
# access_control = generic.load(fd)
fd.close()
err("No active policy. Policy must be specified in command line.")
if access_control.has_key(resource):
security.err("This resource is already labeled.")
# write the data to file
new_entry = { resource : tuple([policyref, label]) }
access_control.update(new_entry)
fd = open(file, "wb")
# generic.dump(access_control, fd)
fd.close()
except security.ACMError:
pass
except:
traceback.print_exc(limit=1)
def add_domain_label(label, configfile, policyref):
try:
# sanity checks: make sure this label can be instantiated later on
ssidref = security.label2ssidref(label, policyref, 'dom')
#sanity checks: make sure this label can be instantiated later on
ssidref = label2ssidref(label, policyref, 'dom')
new_label = "access_control = ['policy=%s,label=%s']\n" % (policyref, label)
if not os.path.isfile(configfile):
security.err("Configuration file \'" + configfile + "\' not found.")
err("Configuration file \'" + configfile + "\' not found.")
config_fd = open(configfile, "ra+")
for line in config_fd:
if not security.access_control_re.match(line):
if not access_control_re.match(line):
continue
config_fd.close()
security.err("Config file \'" + configfile + "\' is already labeled.")
err("Config file \'" + configfile + "\' is already labeled.")
config_fd.write(new_label)
config_fd.close()
except security.ACMError:
except ACMError:
pass
except:
traceback.print_exc(limit=1)
def main (argv):
try:
policyref = None
if len(argv) not in [4,5]:
usage()
label = argv[1]
if len(argv) == 5:
policyref = argv[4]
elif security.on():
policyref = security.active_policy
else:
security.err("No active policy. Policy must be specified in command line.")
if argv[2].lower() == "dom":
configfile = argv[3]
if configfile[0] != '/':
for prefix in [".", "/etc/xen"]:
configfile = prefix + "/" + configfile
if os.path.isfile(configfile):
fd = open(configfile, "rb")
break
if not validate_config_file(configfile):
usage()
else:
add_domain_label(label, configfile, policyref)
elif argv[2].lower() == "res":
resource = argv[3]
add_resource_label(label, resource, policyref)
else:
usage()
except security.ACMError:
pass
except:
traceback.print_exc(limit=1)
if __name__ == '__main__':
main(sys.argv)
+3 -56
View File
@@ -985,56 +985,6 @@ def parseCommandLine(argv):
return (gopts, config)
def config_security_check(config, verbose):
"""Checks each resource listed in the config to see if the active
policy will permit creation of a new domain using the config.
Returns 1 if the config passes all tests, otherwise 0.
"""
answer = 1
# get the domain acm_label
domain_label = None
domain_policy = None
for x in sxp.children(config):
if sxp.name(x) == 'security':
domain_label = sxp.child_value(sxp.name(sxp.child0(x)), 'label')
domain_policy = sxp.child_value(sxp.name(sxp.child0(x)), 'policy')
# if no domain label, use default
if not domain_label and security.on():
domain_label = security.ssidref2label(security.NULL_SSIDREF)
domain_policy = 'NULL'
elif not domain_label:
domain_label = ""
domain_policy = 'NULL'
if verbose:
print "Checking resources:"
# build a list of all resources in the config file
resources = []
for x in sxp.children(config):
if sxp.name(x) == 'device':
if sxp.name(sxp.child0(x)) == 'vbd':
resources.append(sxp.child_value(sxp.child0(x), 'uname'))
# perform a security check on each resource
for resource in resources:
try:
security.res_security_check(resource, domain_label)
if verbose:
print " %s: PERMITTED" % (resource)
except security.ACMError:
print " %s: DENIED" % (resource)
(res_label, res_policy) = security.get_res_label(resource)
print " --> res:"+res_label+" ("+res_policy+")"
print " --> dom:"+domain_label+" ("+domain_policy+")"
answer = 0
return answer
def main(argv):
try:
(opts, config) = parseCommandLine(argv)
@@ -1047,12 +997,9 @@ def main(argv):
if opts.vals.dryrun:
PrettyPrint.prettyprint(config)
else:
if not config_security_check(config, verbose=0):
err("Resource access violation")
else:
dom = make_domain(opts, config)
if opts.vals.console_autoconnect:
console.execConsole(dom)
dom = make_domain(opts, config)
if opts.vals.console_autoconnect:
console.execConsole(dom)
if __name__ == '__main__':
main(sys.argv)
-95
View File
@@ -1,95 +0,0 @@
#============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2006 International Business Machines Corp.
# Author: Bryan D. Payne <bdpayne@us.ibm.com>
#============================================================================
"""Tests the security settings for a domain and its resources.
"""
from xen.util import security
from xen.xm import create
from xen.xend import sxp
def usage():
print "\nUsage: xm dry-run <configfile>\n"
print "This program checks each resource listed in the configfile"
print "to see if the domain created by the configfile can access"
print "the resources. The status of each resource is listed"
print "individually along with the final security decision.\n"
def check_domain_label(config):
"""All that we need to check here is that the domain label exists and
is not null when security is on. Other error conditions are
handled when the config file is parsed.
"""
answer = 0
secon = 0
default_label = security.ssidref2label(security.NULL_SSIDREF)
if security.on():
secon = 1
# get the domain acm_label
dom_label = None
dom_name = None
for x in sxp.children(config):
if sxp.name(x) == 'security':
dom_label = sxp.child_value(sxp.name(sxp.child0(x)), 'label')
if sxp.name(x) == 'name':
dom_name = sxp.child0(x)
# sanity check on domain label
print "Checking domain:"
if (not secon) and (not dom_label):
print " %s: PERMITTED" % (dom_name)
answer = 1
elif (secon) and (dom_label) and (dom_label != default_label):
print " %s: PERMITTED" % (dom_name)
answer = 1
else:
print " %s: DENIED" % (dom_name)
if not secon:
print " --> Security off, but domain labeled"
else:
print " --> Domain not labeled"
answer = 0
return answer
def main (argv):
if len(argv) != 2:
usage()
return
try:
passed = 0
(opts, config) = create.parseCommandLine(argv)
if check_domain_label(config):
if create.config_security_check(config, verbose=1):
passed = 1
else:
print "Checking resources: (skipped)"
if passed:
print "Dry Run: PASSED"
else:
print "Dry Run: FAILED"
except security.ACMError:
pass
if __name__ == '__main__':
main(sys.argv)
-134
View File
@@ -1,134 +0,0 @@
#============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2006 International Business Machines Corp.
# Author: Bryan D. Payne <bdpayne@us.ibm.com>
#============================================================================
"""Show the label for a domain or resoruce.
"""
import sys, os, re
import string
import traceback
#from xml.marshal import generic
from xen.util import security
def usage():
print "\nUsage: xm getlabel dom <configfile>"
print " xm getlabel res <resource>\n"
print " This program shows the label for a domain or resource.\n"
def get_resource_label(resource):
"""Gets the resource label
"""
try:
# read in the resource file
file = security.res_label_filename
if os.path.isfile(file):
fd = open(file, "rb")
# access_control = generic.load(fd)
fd.close()
else:
print "Resource label file not found"
return
# get the entry and print label
if access_control.has_key(resource):
policy = access_control[resource][0]
label = access_control[resource][1]
print "policy="+policy+",label="+label
else:
print "Resource not labeled"
return
except security.ACMError:
pass
except:
traceback.print_exc(limit=1)
def get_domain_label(configfile):
try:
# open the domain config file
fd = None
file = None
if configfile[0] == '/':
fd = open(configfile, "rb")
else:
for prefix in [".", "/etc/xen"]:
file = prefix + "/" + configfile
if os.path.isfile(file):
fd = open(file, "rb")
break
if not fd:
print "Configuration file '"+configfile+"' not found."
return
# read in the domain config file, finding the label line
ac_entry_re = re.compile("^access_control\s*=.*", re.IGNORECASE)
ac_exit_re = re.compile(".*'\].*")
acline = ""
record = 0
for line in fd.readlines():
if ac_entry_re.match(line):
record = 1
if record:
acline = acline + line
if record and ac_exit_re.match(line):
record = 0
fd.close()
# send error message if we didn't find anything
if acline == "":
print "Label does not exist in domain configuration file."
return
# print out the label
(title, data) = acline.split("=", 1)
data = data.strip()
data = data.lstrip("[\'")
data = data.rstrip("\']")
(p, l) = data.split(",")
print data
except security.ACMError:
pass
except:
traceback.print_exc(limit=1)
def main (argv):
try:
if len(argv) != 3:
usage()
return
if argv[1].lower() == "dom":
configfile = argv[2]
get_domain_label(configfile)
elif argv[1].lower() == "res":
resource = argv[2]
get_resource_label(resource)
else:
usage()
except security.ACMError:
traceback.print_exc(limit=1)
if __name__ == '__main__':
main(sys.argv)
+1 -27
View File
@@ -30,7 +30,6 @@ import socket
import warnings
warnings.filterwarnings('ignore', category=FutureWarning)
import xmlrpclib
import traceback
import xen.xend.XendProtocol
@@ -120,11 +119,7 @@ vnet_list_help = "vnet-list [-l|--long] list vnets"
vnet_create_help = "vnet-create <config> create a vnet from a config file"
vnet_delete_help = "vnet-delete <vnetid> delete a vnet"
vtpm_list_help = "vtpm-list <DomId> [--long] list virtual TPM devices"
addlabel_help = "addlabel <label> dom <configfile> Add security label to domain\n <label> res <resource> or resource"
rmlabel_help = "rmlabel dom <configfile> Remove security label from domain\n res <resource> or resource"
getlabel_help = "getlabel dom <configfile> Show security label for domain\n res <resource> or resource"
dry_run_help = "dry-run <configfile> Tests if domain can access its resources"
resources_help = "resources Show info for each labeled resource"
addlabel_help = "addlabel <ConfigFile> <label> Add security label to ConfigFile"
cfgbootpolicy_help = "cfgbootpolicy <policy> Add policy to boot configuration "
dumppolicy_help = "dumppolicy Print hypervisor ACM state information"
loadpolicy_help = "loadpolicy <policy> Load binary policy into hypervisor"
@@ -208,10 +203,6 @@ vnet_commands = [
acm_commands = [
"labels",
"addlabel",
"rmlabel",
"getlabel",
"dry-run",
"resources",
"makepolicy",
"loadpolicy",
"cfgbootpolicy",
@@ -1001,19 +992,6 @@ def xm_block_attach(args):
if len(args) == 5:
vbd.append(['backend', args[4]])
# verify that policy permits attaching this resource
try:
dominfo = server.xend.domain(dom)
domid = sxp.child_value(dominfo, 'domid')
(tmp1, label, tmp2, tmp3) = security.get_ssid(domid)
security.res_security_check(args[1], label)
except security.ACMError, e:
print e.value
sys.exit(1)
except:
traceback.print_exc(limit=1)
sys.exit(1)
server.xend.domain.device_create(dom, vbd)
@@ -1146,10 +1124,6 @@ subcommands = [
'shutdown',
'labels',
'addlabel',
'rmlabel',
'getlabel',
'dry-run',
'resources',
'cfgbootpolicy',
'makepolicy',
'loadpolicy',
-70
View File
@@ -1,70 +0,0 @@
#============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2006 International Business Machines Corp.
# Author: Bryan D. Payne <bdpayne@us.ibm.com>
#============================================================================
"""List the resource label information from the global resource label file
"""
import sys, os
import string
import traceback
#from xml.marshal import generic
from xen.util import security
def usage():
print "\nUsage: xm resource\n"
print " This program lists information for each resource in the"
print " global resource label file\n"
def print_resource_data(access_control):
"""Prints out a resource dictionary to stdout
"""
for resource in access_control:
(policy, label) = access_control[resource]
print resource
print " policy: "+policy
print " label: "+label
def get_resource_data():
"""Returns the resource dictionary.
"""
file = security.res_label_filename
if not os.path.isfile(file):
security.err("Resource file not found.")
fd = open(file, "rb")
# access_control = generic.load(fd)
fd.close()
return access_control
def main (argv):
try:
access_control = get_resource_data()
print_resource_data(access_control)
except security.ACMError:
pass
except:
traceback.print_exc(limit=1)
if __name__ == '__main__':
main(sys.argv)
-134
View File
@@ -1,134 +0,0 @@
#============================================================================
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General Public
# License as published by the Free Software Foundation.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#============================================================================
# Copyright (C) 2006 International Business Machines Corp.
# Author: Bryan D. Payne <bdpayne@us.ibm.com>
#============================================================================
"""Remove a label from a domain configuration file or a resoruce.
"""
import sys, os, re
import string
import traceback
#from xml.marshal import generic
from xen.util import security
def usage():
print "\nUsage: xm rmlabel dom <configfile>"
print " xm rmlabel res <resource>\n"
print " This program removes an acm_label entry from the 'configfile'"
print " for a domain or from the global resource label file for a"
print " resource. If the label does not exist for the given domain or"
print " resource, then rmlabel fails.\n"
def rm_resource_label(resource):
"""Removes a resource label from the global resource label file.
"""
try:
# read in the resource file
file = security.res_label_filename
if os.path.isfile(file):
fd = open(file, "rb")
# access_control = generic.load(fd)
fd.close()
else:
security.err("Resource file not found, cannot remove label!")
# remove the entry and update file
if access_control.has_key(resource):
del access_control[resource]
fd = open(file, "wb")
# generic.dump(access_control, fd)
fd.close()
else:
security.err("Label does not exist in resource label file.")
except security.ACMError:
pass
except:
traceback.print_exc(limit=1)
def rm_domain_label(configfile):
try:
# open the domain config file
fd = None
file = None
if configfile[0] == '/':
fd = open(configfile, "rb")
else:
for prefix in [".", "/etc/xen"]:
file = prefix + "/" + configfile
if os.path.isfile(file):
fd = open(file, "rb")
break
if not fd:
security.err("Configuration file '"+configfile+"' not found.")
# read in the domain config file, removing label
ac_entry_re = re.compile("^access_control\s*=.*", re.IGNORECASE)
ac_exit_re = re.compile(".*'\].*")
file_contents = ""
comment = 0
removed = 0
for line in fd.readlines():
if ac_entry_re.match(line):
comment = 1
if comment:
removed = 1
line = "#"+line
if comment and ac_exit_re.match(line):
comment = 0
file_contents = file_contents + line
fd.close()
# send error message if we didn't find anything to remove
if not removed:
security.err("Label does not exist in domain configuration file.")
# write the data back out to the file
fd = open(file, "wb")
fd.writelines(file_contents)
fd.close()
except security.ACMError:
pass
except:
traceback.print_exc(limit=1)
def main (argv):
try:
if len(argv) != 3:
usage()
return
if argv[1].lower() == "dom":
configfile = argv[2]
rm_domain_label(configfile)
elif argv[1].lower() == "res":
resource = argv[2]
rm_resource_label(resource)
else:
usage()
except security.ACMError:
traceback.print_exc(limit=1)
if __name__ == '__main__':
main(sys.argv)
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.