1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Blacklist special file 31 */ 32 33 #include <sys/types.h> 34 #include <sys/conf.h> 35 #include <sys/stat.h> 36 #include <sys/modctl.h> 37 #include <sys/kmem.h> 38 #include <sys/ddi.h> 39 #include <sys/sunddi.h> 40 #include <sys/open.h> 41 #include <sys/policy.h> 42 #include <sys/fm/protocol.h> 43 #include <sys/bl.h> 44 45 static dev_info_t *bl_dip; /* private copy of devinfo pointer */ 46 47 static int 48 bl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 49 { 50 switch (cmd) { 51 case DDI_ATTACH: 52 break; 53 case DDI_RESUME: 54 return (DDI_SUCCESS); 55 default: 56 return (DDI_FAILURE); 57 } 58 59 if (ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR, 60 ddi_get_instance(dip), DDI_PSEUDO, 0) != DDI_SUCCESS) 61 return (DDI_FAILURE); 62 63 bl_dip = dip; 64 return (DDI_SUCCESS); 65 } 66 67 /*ARGSUSED*/ 68 static int 69 bl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 70 { 71 switch (cmd) { 72 case DDI_DETACH: 73 break; 74 case DDI_SUSPEND: 75 return (DDI_SUCCESS); 76 default: 77 return (DDI_FAILURE); 78 } 79 80 ddi_remove_minor_node(bl_dip, NULL); 81 return (DDI_SUCCESS); 82 } 83 84 /*ARGSUSED*/ 85 static int 86 bl_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 87 { 88 int rc = DDI_SUCCESS; 89 90 switch (infocmd) { 91 case DDI_INFO_DEVT2DEVINFO: 92 *result = bl_dip; 93 break; 94 95 case DDI_INFO_DEVT2INSTANCE: 96 *result = (void *)(uintptr_t)getminor((dev_t)arg); 97 break; 98 99 default: 100 *result = NULL; 101 rc = DDI_FAILURE; 102 } 103 104 return (rc); 105 } 106 107 /*ARGSUSED*/ 108 static int 109 bl_open(dev_t *devp, int flag, int otyp, struct cred *credp) 110 { 111 if (otyp != OTYP_CHR) 112 return (EINVAL); 113 114 if (secpolicy_blacklist(credp) != 0) 115 return (EPERM); 116 117 return (0); 118 } 119 120 /*ARGSUSED*/ 121 static int 122 bl_ioctl(dev_t dev, int cmd, intptr_t data, int flag, cred_t *cred, int *rvalp) 123 { 124 bl_req_t blr; 125 nvlist_t *fmri; 126 const char *scheme; 127 char class[128]; 128 char *buf; 129 int err; 130 131 #ifdef _SYSCALL32 132 if (get_udatamodel() != DATAMODEL_NATIVE) { 133 bl_req32_t blr32; 134 135 if (copyin((void *)data, &blr32, sizeof (bl_req32_t)) != 0) 136 return (EFAULT); 137 138 blr.bl_fmri = (caddr_t)(uintptr_t)blr32.bl_fmri; 139 blr.bl_fmrisz = blr32.bl_fmrisz; 140 141 blr.bl_class = (caddr_t)(uintptr_t)blr32.bl_class; 142 } else 143 #endif 144 { 145 if (copyin((void *)data, &blr, sizeof (bl_req_t)) != 0) 146 return (EFAULT); 147 } 148 149 if (blr.bl_fmri == NULL || blr.bl_fmrisz > BL_FMRI_MAX_BUFSIZE || 150 blr.bl_class == NULL) 151 return (EINVAL); 152 153 if (copyinstr(blr.bl_class, class, sizeof (class), NULL) != 0) 154 return (EFAULT); 155 156 buf = kmem_zalloc(blr.bl_fmrisz, KM_SLEEP); 157 if (copyin(blr.bl_fmri, buf, blr.bl_fmrisz) != 0) { 158 kmem_free(buf, blr.bl_fmrisz); 159 return (EFAULT); 160 } 161 162 err = nvlist_unpack(buf, blr.bl_fmrisz, &fmri, KM_SLEEP); 163 kmem_free(buf, blr.bl_fmrisz); 164 if (err != 0) 165 return (err); 166 167 if (nvlist_lookup_string(fmri, FM_FMRI_SCHEME, (char **)&scheme) != 0) { 168 nvlist_free(fmri); 169 return (EINVAL); 170 } 171 172 switch (cmd) { 173 case BLIOC_INSERT: 174 case BLIOC_DELETE: 175 err = blacklist(cmd, scheme, fmri, class); 176 break; 177 default: 178 err = ENOTSUP; 179 } 180 181 nvlist_free(fmri); 182 return (err); 183 184 } 185 186 static struct cb_ops bl_cb_ops = { 187 bl_open, /* open */ 188 nulldev, /* close */ 189 nodev, /* strategy */ 190 nodev, /* print */ 191 nodev, /* dump */ 192 nodev, /* read */ 193 nodev, /* write */ 194 bl_ioctl, /* ioctl */ 195 nodev, /* devmap */ 196 nodev, /* mmap */ 197 nodev, /* segmap */ 198 nochpoll, /* poll */ 199 ddi_prop_op, /* cb_prop_op */ 200 0, /* streamtab */ 201 D_NEW | D_MP | D_64BIT /* Driver compatibility flag */ 202 }; 203 204 static struct dev_ops bl_ops = { 205 DEVO_REV, /* devo_rev */ 206 0, /* devo_refcnt */ 207 bl_getinfo, /* devo_getinfo */ 208 nulldev, /* devo_identify */ 209 nulldev, /* devo_probe */ 210 bl_attach, /* devo_attach */ 211 bl_detach, /* devo_detach */ 212 nodev, /* devo_reset */ 213 &bl_cb_ops, /* devo_cb_ops */ 214 (struct bus_ops *)0, /* devo_bus_ops */ 215 NULL /* devo_power */ 216 }; 217 218 static struct modldrv modldrv = { 219 &mod_driverops, "blacklist driver %I%", &bl_ops, 220 }; 221 222 static struct modlinkage modlinkage = { 223 MODREV_1, &modldrv, NULL 224 }; 225 226 int 227 _init(void) 228 { 229 return (mod_install(&modlinkage)); 230 } 231 232 int 233 _info(struct modinfo *modinfop) 234 { 235 return (mod_info(&modlinkage, modinfop)); 236 } 237 238 int 239 _fini(void) 240 { 241 return (mod_remove(&modlinkage)); 242 } 243