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